home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / SYQUEST / SQHINST / NAHDI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  91.2 KB  |  3,064 lines

  1. ; Apr 11 1989 v3.00'
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST                :
  6. ;    Copyright 1985,1986,1987,1988,1989 Atari Corp.            :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;----------------
  13. ;
  14. ;  Conditional Assembly Switches
  15. ;
  16. format        equ    0        ; Format code
  17. mdsense        equ    0        ; Mode Sense code
  18. ospool        equ    1        ; increase size of OS pool for ROM
  19.  
  20.  
  21. ;
  22. ;-------------------- Edit History ------------------------
  23.  
  24. ;------------------
  25. ;                                    :
  26. ;  9-Apr-1985 lmd    Hacked it up.  "Gee, it seems to work ..."    :
  27. ; 14-Apr-1985 lmd    linked with BIOS (***FOR NOW***)        :
  28. ; 20-Apr-1985 lmd    hacked for WD controller (now, wired...)    :
  29. ; 24-Jun-1985 jwt    hacked for Adaptec, new kludge board        :
  30. ; 01-Jul-1985 jwt    seems to work, add more formatting and more    :
  31. ;             detailed error reporting            :
  32. ; 22-Jul-1985 jwt    change timing of wdc/wdl at start of command,    :
  33. ;             added extra move.w $8a,wdl to change A1    :
  34. ; 23-Jul-1985 jwt    use a move.l instruction for all wdc/wdl write    :
  35. ;             pairs since it changes A1 quickly enough that    :
  36. ;             the (old) DMA chip does not incorrectly    :
  37. ;             generate two chip selects            :
  38. ; 26-Sep-1985 jwt v0.05    support multiple ACSI devices            :
  39. ;            separate timeouts for command packet and    :
  40. ;             operation                    :
  41. ; 01-Oct-1985 jwt v0.06    added some AUXout serial debug messages        :
  42. ;            was responding to one more drive than was there    :
  43. ; 07-Oct-1985 jwt v0.07    added support for multiple partitions/drive    :
  44. ; 11-Oct-1985 jwt v0.08 added delay loop after pread for completion    :
  45. ;             byte                        :
  46. ; 19-Oct-1985 jwt v0.09    remove format and simple commands from resident :
  47. ;             part                        :
  48. ;            conditional assembly for default size        :
  49. ;            added count parameter to pread            :
  50. ; 22-Oct-1985 jwt v0.10    make certain qdone returns d0=-1 on timeout    :
  51. ;            add bits to read/write flag for:        :
  52. ;             retry disable (bit 2)                :
  53. ;             physical unit operation (bit 3)        :
  54. ;            add pun_ptr to TOS global variables        :
  55. ; 24-Oct-1985 jwt v0.11    add critical error call on errors        :
  56. ; 30-Jan-1986 lmd v0.12    increase OS pool by 128 chunks for ROM release    :
  57. ;             of 11/20/85                    :
  58. ;          jwt    stay resident if any physical units found    :
  59. ;             rather than if any GEM partitions found    :
  60. ; 05-Feb-1986 jwt    call critical error handler on errors unless    :
  61. ;             no-retry bit is set                :
  62. ;            conditional assembly format code        :
  63. ;            remove transfer only to even byte boundary    :
  64. ;             restriction                    :
  65. ;            remove transfer less than 128K restriction    :
  66. ;            check for 0 length transfer            :
  67. ; 06-Feb-1986 jwt v0.13    use register based accesses for wdc and wdl    :
  68. ; 25-Mar-1986 lmd v0.14 Enforce .005 (200th) sec delay between        :
  69. ;             successive calls to _do_rw().  SCSI adapter    :
  70. ;             board eats the controller's completion byte,    :
  71. ;             so we have to delay for it.            :
  72. ; 24-Apr-1986 lmd v1.1    Hack pool_install code to increase pool for    :
  73. ;             other ROM releases of the system.        :
  74. ; 24-Apr-1986 lmd v1.4    Print nasty messages for old disk-based and    :
  75. ;             unauthorized ROM-based systems.        :
  76. ; 23-Jun-1987 lmd v1.5  Fix date-check in nasty-OS-message code; wrong    :
  77. ;             offset into the OS header (now $1e).        :
  78. ; 06-Nov-1987 akp v1.7    Added procedure findpackages and call to it.    :
  79. ; 10-Nov-1987 akp    Changed source to MADMAC format.        :
  80. ;            Removed format flag from top of file.        :
  81. ; 24-Nov-1987 akp    Really made v1.7 work.                :
  82. ; 19-Feb-1988 ml    Added format and mode sense code for use in     :
  83. ;             HDX  (It's conditional, code will only be    :
  84. ;             included for ahdi.prg, and not shdriver.sys).    :
  85. ; 26-May-1988 ml    Added request sense code for use in HDX 3.0    :
  86. ;             for SR444 (Syquest drive).            :
  87. ; ??-Aug-1988 ml  v2.0    Attempted to add code for removable media.    :
  88. ; 07-Sep-1988 ml    Found out that shouldn't move code around too    :
  89. ;             much.  Labels i_sasi and i_sasi1 are used to    :
  90. ;             determine which part of this program will be    :
  91. ;             reserved at Ptermres().  All text and data to    :
  92. ;             be reserved should appear between these two    :
  93. ;             labels.                    :
  94. ; 31-Oct-1988 ml    It seemed to work well.  Now AHDI can handle    :
  95. ;             both removable and non-removable hard disks.    :
  96. ;            It can handle hard disks partitioned in    GEMDOS    :
  97. ;             format or MSDOS 3.x format.              :
  98. ;            Code for executing programs in the AUTO folder     :
  99. ;             and packages in RAM, and code for bringing up    :
  100. ;             AES have been deleted.  Instead, AHDI returns    :
  101. ;             to TOS ROMs and let them handle those tasks.    :
  102. ; 01-Dec-1988 ml    Modified _sasi_rw so that it will look for a     :
  103. ;             LONG record number after the device number, if :
  104. ;             the WORD record number == -1.  This allows the    :
  105. ;             caller of Rwabs to address pass 32Mb.        :
  106. ;             Though the underlying routine is the same, the    :
  107. ;             caller has to call Lrwabs from the high level,    :
  108. ;             not Rwabs for this to work.            :
  109. ; 02-Dec-1988 ml    Modified the way we check whether we should jam    :
  110. ;             d7 for further boot before returning to TOS    :
  111. ;             ROMs.  The system build date is being checked    :
  112. ;             instead of the OS version number.  This is    :
  113. ;             necessary because there seems to be confusion    :
  114. ;             about version numbers of some released ROMS.    :
  115. ; 05-Dec-1988 ml    If OS wasn't built before 4/22/1987, when     :
  116. ;             returning to TOS ROMs, jam d7 with the last     :
  117. ;             unit that was processed, instead of magic #.    :
  118. ; 08-Dec-1988 ml    If ospool code is included, make sure 'poolbuf'    :
  119. ;             is the last label in the program to be kept.    :
  120. ;             The code uses the memory after that label as    :
  121. ;             a buffer.  Whatever is after 'poolbuf' will be :
  122. ;             overwritten.                    :
  123. ; 04-Jan-1989 ml    Modified to handle more than 4 partitions per    :
  124. ;             physical unit.  The method used is the same as    :
  125. ;             used in MSDOS 3.3 (ie., by implementing a     :
  126. ;             linked list of logical drives).  There is a     :
  127. ;             type of partition called the EXTENDED GEMDOS    :
  128. ;             PARTITION which is head of the linked list.    :
  129. ;             This new type of partition is specified by the    :
  130. ;             value "XGM" in the p_id field of the partition    :
  131. ;             map.                        :
  132. ; 22-Feb-1989 ml v2.07a    Modified _fdone() and _qdone() to use 200 hz    :
  133. ;             clock for timeout loop.  This would keep the    :
  134. ;             timeout constant over different machines.    :
  135. ; 02-Mar-1989 ml v2.08a Moved pbuf up with regular declarations.  It    :
  136. ;             should stay resident.  Added a cookie pointer    :
  137. ;             for people to check if they have gotten this    :
  138. ;             new version of ahdi.                :
  139. ; 03-Mar-1989 ml    Changed cookie to 'AHDI'.  It will stay that     :
  140. ;             way.  Added version #, a long, right after    :
  141. ;             cookie ptr.                      :
  142. ;             Example: 19890208                :
  143. ;                 1989 - year 1989;            :
  144. ;                 02 - major version #;            :
  145. ;                 08 - minor version #;            :
  146. ; 06-Mar-1989 ml     Enforced 0.005 sec delay between driver calls.    :
  147. ;             Delay only when neccessary before 1st command    :
  148. ;             byte is sent, and update timer when command is    :
  149. ;             done.  New routine _delay().  Update timer     :
  150. ;             code is added in _endcmd().            :
  151. ; 07-Mar-1989 ml    More optimization done on low-level driver.    :
  152. ;             Use registers instead of wdlwdc when accessing    :
  153. ;             DMA registers, etc...                :
  154. ; 09-Mar-1989 ml    Forced driver to stay around even when no drive    :
  155. ;             is found.                    :
  156. ;            Made number of drive to reserve for each ACSI     :
  157. ;             Syquest drive patchable.            :
  158. ;             Magic number $f0ad is used to denote a version    :
  159. ;             with patchable variables.            :
  160. ;             Version number (same as one after the cookie    :
  161. ;             pointer) is stored after magic # $f0ad.    :
  162. ; 10-Mar-1989 ml    Made number of memory chunks to add to ospool    :
  163. ;             patchable.                    :
  164. ; 13-Mar-1989 ml v2.09a    If there is no cartridge in a Syquest drive,    :
  165. ;             return drive not ready, and pass to critical    :
  166. ;             error handler.                    :
  167. ; 29-Mar-1989 ml v2.10a Verion number is now a word, MMmm.        :
  168. ;             (MM - major #; mm - minor #)            :
  169. ;            Added in checks to see if enough memory is    :
  170. ;             allocated for ospool installation and big    :
  171. ;             GEMDOS buffer lists.                :
  172. ; 30-Mar-1989 ml    If there is not enough memory for big GEMDOS    :
  173. ;             buffer lists, make maximum sector size = 512.    :
  174. ;             This guarantees that the regular partitions     :
  175. ;             are still accessible.                :
  176. ;            If there is not enough memory to install amount    :
  177. ;             of OS pool requested. NONE would be installed. :
  178. ;            Variable 'poolbuf' is gone.            :
  179. ; 04-Apr-1989 ml    Sped up media change.  Refer to comments at    :
  180. ;             _sasi_mediach.                    :
  181. ; 11-Apr-1989 ml v3.00    Made version # consistent with HDX and HINSTALL.:
  182. ; 15-May-1989 ml    Initialize sendata buffer to be all 0's every    :
  183. ;             time before _inquiry() is called.        :
  184. ;            Fixed the bug for Dsetpath() (move.l #rootpath    :
  185. ;             instead of move.l rootpath).            :
  186. ;------------------------------------------------------------------------
  187.  
  188.  
  189. ;
  190. ;------------  Equates and Declarations--------------
  191.  
  192. etv_critic    equ    $404        ; critical error handoff vector
  193. phystop        equ    $42e        ; physical top of memory
  194. flock        equ    $43e        ; FIFO lock variable
  195. _bootdev    equ    $446        ; default boot device
  196. hdv_init    equ    $46a        ; hdv_init()    ** UNUSED **
  197. hdv_bpb        equ    $472        ; hdv_bpb(dev)
  198. hdv_rw        equ    $476        ; hdv_rw(rw, buf, count, recno, dev)
  199. hdv_boot    equ    $47a        ; hdv_boot()    ** UNUSED **
  200. hdv_mediach    equ    $47e        ; hdv_mediach(dev)
  201. _bufl        equ    $4b2        ; 2 buffer-list headers
  202. _hz_200        equ    $4ba        ; system 200hz timer
  203. _drvbits    equ    $4c2        ; block device bitVector
  204. _dskbufp    equ    $4c6        ; pointer to common disk buffer
  205. _sysbase    equ    $4f2        ; -> base of OS
  206. pun_ptr        equ    $516        ; number of physical units
  207.  
  208. ;+
  209. ; Restraints 
  210. ;-
  211. MAXUNITS    equ    14        ; max # of log units w/o drv A & B
  212. MAXACSI        equ    8        ; maximum number of ACSI devices
  213. MAXSECTORS    equ    254        ; maximum no. of sectors at one gulp
  214.  
  215. ;+
  216. ; Offsets to ...
  217. ;-
  218. DOSPM        equ    $1be        ; MSDOS boot sect's partition map
  219. DOSSIG        equ    $1fe        ; MSDOS boot sect's signature
  220. HDSIZ        equ    $1c2        ; offset to GEMDOS root sect's 
  221.                     ; hard disk size
  222.  
  223. ;+
  224. ; Constants and Variables
  225. ;-
  226. SIG        equ    $55aa        ; signature for valid MSDOS boot sects
  227. NRETRIES    equ    3        ; #retries-1
  228. MAXNPART    equ    3        ; #partition entries in root sect - 1
  229. BPBLEN        equ    18        ; length of bpb entry in bytes
  230. FATLEN        equ    64        ; max fat size = 64 sectors
  231.                     ; (for 16Mb drive, 2 spc, 512 bps)
  232. SERLEN        equ    3        ; length of a serial # in bytes
  233. CHKDATE        equ    $04221987    ; ROM date for bootstop checking
  234.  
  235. ;+
  236. ; BIOS error codes
  237. ;-
  238. EDRVNR        equ    -2        ; driver not ready
  239. EWRITF        equ    -10        ; write fault
  240. EREADF        equ    -11        ; read fault
  241. EWRPRO        equ    -13        ; write on write-protected media
  242. E_CHNG        equ    -14        ; media change detected
  243. CRITRETRY    equ    $00010000    ; "retry" return code
  244.  
  245. ;+
  246. ; SCSI error codes
  247. ;-
  248. DRVNRDY        equ    $4        ; drive not ready
  249. WRTPRTD        equ    $27        ; write on write-protected media
  250. MDMCHGD        equ    $28        ; media change detected
  251.  
  252. ;+
  253. ; Number of bytes per Buffer Control Block (excluding the data block itself)
  254. ;
  255. ; struct_bcb {
  256. ;     struct_bcb    *b_link;    /* 4 bytes */
  257. ;    int        b_neg1;        /* 2 bytes */
  258. ;    int        b_private[5];    /* 10 bytes */
  259. ;    char        *b_bufr;    /* 4 bytes */
  260. ; };
  261. ;
  262. ; For GEMDOS buffer lists.
  263. ;-
  264. BCBLEN        equ    20
  265.  
  266. ;+
  267. ; for extension of os pool
  268. ;-
  269. chunksiz    equ     66        ; #bytes/chunk
  270. chunkno        equ     4        ; chunk# (4 16-byte chunks)
  271.  
  272.  
  273. ;
  274. ;----------------
  275. ;
  276. ;  Entry points:
  277. ;
  278. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  279. ;    +4   Boot entry point (from driver file off of C:)
  280. ;    +8   Reserved for future use
  281. ;    +$C  $F0AD magic number
  282. ;    +$E  version number
  283. ;    +$12 # chunks of ospool to add
  284. ;    +$14 # of sqnpart entries that follows
  285. ;    +$16 first sqnpart entry
  286. ;
  287. ;  if bootloaded, d0 = # bytes allocated by boot code.
  288. ;
  289. i_sasi:    bra    gboot            ; GEMDOS entry-point
  290.     bra    iboot            ; Boot entry-point
  291.     bra    iboot            ; (unused, reserved)
  292.  
  293.  
  294. ;----------------
  295. ;
  296. ;  Patchable variables
  297. ;
  298. magicnum:    dc.w    $f0ad        ; wasn't here in previous releases
  299. vernum:        dc.w    $0300        ; version number
  300. numchunks:    dc.w    128        ; # chunks of ospool to add
  301. minbigsect:    dc.w    512        ; minimum size of a big sector
  302. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  303. minsqnpart:    dcb.b    MAXACSI,1    ; minimum # drives for removable unit
  304. .even
  305.  
  306. ;----------------
  307. ;
  308. ;  GEMDOS entry;
  309. ;    find amount of memory availble and store in d0.l
  310. ;
  311. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  312.     move.l    4(a2),d0        ; d0 = available memory
  313.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  314.     sub.l    #$0100,d0
  315.     bra    i_sasi1            ; (continue with normal initialization)
  316.  
  317.  
  318. ;----------------
  319. ;
  320. ;  Boot entry;
  321. ;    set "bootloaded", record base address from boot loader, 
  322. ;    and continue with normal boot process.
  323. ;
  324. iboot:    st    bootloaded        ; boot entry-point, set flag
  325.     sub.l    #$1c,d0            ; memory available -= file header
  326.     move.l    a2,baseaddr        ; install base address
  327.                     ; a2 = beginning addr of this block
  328.     bra    i_sasi1            ; (continue with normal initialization)
  329.  
  330.  
  331. ;
  332. ;--------------- Driver State --------------------
  333.  
  334.         dc.b    13,'AHDI : Apr 11 1989 v3.00'
  335.         dc.b    13,10,$bd,'Atari Corp. 1985, 1986, 1987, 1988, 1989'
  336.         dc.b    13,10,0,$1A
  337. .even
  338.  
  339. _puns:
  340. puns:        dc.w    0        ; # of physical units on user's system
  341.  
  342. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  343. _pun:
  344. pun:        dcb.b    MAXUNITS,0    ; physical unit table
  345. .even
  346.  
  347. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  348. _partstart:
  349. start:        dcb.l    MAXUNITS,0    ; partition start table
  350.  
  351. _cookie:                ; *** DON'T CHANGE ***
  352. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  353.  
  354. _cookptr:
  355. cookptr:    dc.l    0        ; pointer to cookie
  356.  
  357. _versn:
  358. versn:        dc.w    $0300        ; version number: MMmm
  359.  
  360. _maxssz:
  361. maxssz:        dc.w    512        ; maximum sector size allowed
  362.         dcb.l    16,0        ; reserved for future use
  363.  
  364. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  365. mcflgs:    dcb.b    MAXUNITS,2        ; media change flag table
  366. xst:    dcb.b    MAXUNITS,1        ; drive existence flag table
  367. serno:    dcb.b    MAXUNITS*SERLEN,0    ; serial number table
  368. sratio:    dcb.b    MAXUNITS,1        ; log sect size : phys sect size tbl
  369. fatsum:    dcb.b    MAXUNITS*FATLEN,0    ; FAT checksum table
  370. fatst:    dcb.w    MAXUNITS,0        ; starting sector # of last FAT
  371. fatend:    dcb.w    MAXUNITS,0        ; ending sector # of last FAT
  372.  
  373. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  374. memalloc:    dc.l    0        ; total memory available if bootloaded
  375. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  376. tokeep:        dc.l    0        ; amount memory to keep
  377. preadret:    dc.w    0        ; return code from pread
  378.  
  379. cpun:        dc.w    0        ; current physical unit
  380. npart:        dc.w    0        ; number of partitions found
  381. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  382.  
  383. strec:        dc.l    0        ; starting sector to read/write
  384. endrec:        dc.l    0        ; last sector to read/write
  385. stbuf:        dc.l    0        ; starting address of buffer
  386. rmbits:        dc.b    0        ; bit map - 1: unit is removable
  387. scsi:        dc.b    0        ; bit map - 1: embedded SCSI drive
  388.  
  389. _retries:    dc.w    NRETRIES    ; number of retries to do
  390. retrycnt:    dc.w    1        ; retry counter
  391.  
  392. o_bpb:        dc.l    1
  393. o_rw:        dc.l    1
  394. o_mediach:    dc.l    1
  395.  
  396. sendata:    dcb.b    16,0        ; buffer for request sense
  397.  
  398. lastacstm:    dc.l    0        ; controller last accessed time
  399. lastmdctm:    dc.l    0        ; time media change was last called
  400. pbuf:        dc.l    0        ; ptr to start of root sector image
  401. fsiz:        dc.w    0        ; FAT size in sectors
  402. fatrec:        dc.w    0        ; 2nd FAT starting sector
  403. sizr:        dc.w    1        ; ratio of log : phys sector size
  404. temp:        dc.l    0        ; temporary storage
  405. savssp:        dc.l    1        ; (saved SSP)
  406. mcrw:        dc.b    0        ; if TRUE, r/w returns media change
  407. ext:        dc.b    0        ; if =0, not processing ext partition
  408.  
  409. extrt:        dc.l    0        ; starting sector of ext DOS partition
  410. extvol:        dc.l    0        ; offset wrt ext DOS partition
  411. pbpb:        dc.w    0        ; partition # for dev
  412. .even
  413.  
  414.  
  415. ;
  416. ;------------------ Front End ------------------
  417.  
  418. ;----------------
  419. ;
  420. ;  Return pointer to BPB (or NULL)
  421. ;
  422. ;    Synopsis:    LONG hbpb(dev)
  423. ;        WORD dev;    4(sp).w
  424. ;
  425. hbpb:    move.w    4(sp),d0        ; d0 = devno
  426.     clr    d1            ; d1 = 0, physical op not possible
  427.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  428.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  429.     bra.s    check_dev        ; do it
  430.  
  431.  
  432. ;----------------
  433. ;
  434. ;  Read or write logical sectors
  435. ;
  436. ;    Synopsis:    LONG rw(rw, buf, count, recno, dev)
  437. ;        WORD rw;    $4(sp).w
  438. ;        char *buf;    $6(sp).l
  439. ;        WORD count;    $a(sp).w
  440. ;        WORD recno;    $c(sp).w
  441. ;        WORD dev;    $e(sp).w
  442. ;
  443. hrw:    move.w    $e(sp),d0        ; d0 = devno
  444.     move.w    4(sp),d1        ; d1 includes physical device flag
  445.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  446.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  447.     bra.s    check_dev        ; do it
  448.  
  449.  
  450. ;----------------
  451. ;
  452. ;  Check for media change
  453. ;
  454. ;    Synopsis:    LONG mediach(dev)
  455. ;        WORD dev;    4(sp).W
  456. ;
  457. hmediach:
  458.     move.w    4(sp),d0        ; d0 = devno
  459.     clr    d1            ; physical operation not possible
  460.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  461.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  462.  
  463.  
  464. ;----------------
  465. ;
  466. ;  check_dev - use handler, or pass vector through
  467. ;
  468. ;  Passed:    d0.w = device#
  469. ;        d1, bit 3  1=physical operation
  470. ;        a0 ->  old handler
  471. ;        a1 ->  new handler
  472. ;        a5 ->  $0000 (zero-page ptr)
  473. ;
  474. ;  Jumps-to:    (a1) if dev in range for this handler
  475. ;        (a0) otherwise
  476. ;
  477. check_dev:
  478.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  479.     bmi.s    chkd_f            ; if lower, not one of ours
  480.  
  481.     btst    #3,d1            ; is this a physical unit operation?
  482.     beq.s    chkd_a            ; if not set, go to chkd_a
  483.  
  484.     cmp    puns,d0            ; compare unit num to num units exist
  485.     bge.s    chkd_f            ; if unit num too big, not one of ours
  486.     bra.s    chkd_s            ; else it IS one of of ours
  487.  
  488. chkd_a:    lea    pun,a2            ; pointer to pun map
  489.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  490.     bmi.s    chkd_f
  491. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  492. chkd_f:    jmp    (a0)            ; do it
  493.  
  494.  
  495. ;
  496. ;------------------ Medium-Level Driver ----------------
  497.  
  498. ;----------------
  499. ;
  500. ;  Return BPB for logical device
  501. ;
  502. ;    Synopsis:    LONG _sasi_bpb(dev)
  503. ;        WORD dev;    $4(sp).w
  504. ;
  505. ;    Returns:    NULL, or a pointer to the BPB buffer
  506. ;
  507. ; 10-21-88    ml.    I am not making a special case for non-removable
  508. ;            hard disk, because if a program uses Allan's
  509. ;            program to force a media change, the program 
  510. ;            should be getting the "Real" AND "New" BPB.
  511. ;            (The old (v1.7 and before) AHDI only index into
  512. ;            the bpbs table and return the pointer, without
  513. ;            actually go and read the boot sector of the dev.)
  514. ;
  515. _sasi_bpb:
  516.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  517. bpbst:    move.w    4(sp),d1        ; d1 = device number
  518.     lea    pun,a0            ; a0 = ptr to pun table
  519.     adda.w    d1,a0            ; a0 = ptr to pun @ dev's entry
  520.     clr.w    d2            ; coerce byte to word
  521.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  522.  
  523.     lea    xst,a1            ; a0 = ptr to drive existence table
  524.     tst.b    (a1,d1.w)        ; does drive exist?
  525.     bne.s    bpbgo            ; if it does, go on normally
  526.                     ; else, see if it really doesn't exist
  527.     movem.w    d1-d2,-(sp)        ; else save registers
  528.     move.w    d2,-(sp)        ; physical unit number
  529.     bsr    testunit        ; verify by doing test unit ready
  530.     addq.l    #2,sp            ; cleanup stack
  531.     movem.w    (sp)+,d1-d2        ; restore registers
  532.     tst.w    d0            ; return good status?
  533.     beq    badbpb            ; if yes, ie. medium has not changed
  534.                     ; therefore, dev still doesn't exist
  535.     moveq    #1,d0            ; else medium may have changed
  536.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  537.     bra.s    bpbst            ; restart procedure
  538.  
  539. bpbgo:    move.w    d2,cpun            ; cpun = pun(dev)
  540.     move.l    _dskbufp,pbuf        ; pbuf = ptr to 2nd half of 1K disk buf
  541.     add.l    #512,pbuf
  542.  
  543. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  544.     move.w    #1,-(sp)        ; return media change if detected
  545.     move.w    cpun,-(sp)        ; physical unit number
  546.     move.l    pbuf,-(sp)        ; buffer to read into
  547.     move.w    #1,-(sp)        ; read in 1 sector
  548.     clr.l    -(sp)            ; from sector 0
  549.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  550.     adda    #14,sp
  551.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  552.     tst    d0            ; pread successful?
  553.     beq.s    bpb0            ; if yes, go on normally
  554.  
  555. bpberr:    cmpi.w    #E_CHNG,d0        ; is media change detected?
  556.     beq.s    bpbchg            ; if so, set mcflgs
  557.                     ; else call up error handler
  558.     move.l    a0,-(sp)        ; save ptr to pun(dev)
  559.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  560.     bsr    critic            ; call up critical error handler
  561.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  562.     cmpi.l    #CRITRETRY,d0        ; retry?
  563.     beq.s    bpb00            ; if so, go and try again
  564.     bra    badbpb            ; else return no BPB
  565.  
  566. bpbchg:    move.b    #1,d0            ; d0.b = media may be changed
  567.     move.w    4(sp),d1        ; d1.w = device number
  568.     move.b    cpun+1,d2        ; d2.b = physical unit number
  569.     bsr    s_mc_xst        ; go set mcflgs and xst flags
  570.     bra    bpbst            ; restart procedure
  571.  
  572. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  573.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  574. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  575.     bne.s    bpb2
  576.     addq.w    #1,pbpb
  577.     bra.s    bpb1
  578.  
  579. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  580.     movea.l    pbuf,a0            ; a0 = ptr to beginning of root sector
  581.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  582.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  583.     bsr    dosbpb            ; else, handle it the DOS way
  584.     bra.s    bpb4            ; else, go get the bpb
  585. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  586.     bsr    gembpb            ; handle it the GEMDOS way
  587. bpb4:    tst.w    d0            ; successful?
  588.     beq.s    bpbnf            ; if =0, no valid BPB found
  589.     bpl.s    bpb5            ; if +ive, valid BPB found
  590.     cmpi.w    #E_CHNG,d0        ; else media changed?
  591.     beq.s    bpbchg            ; if so, restart procedure
  592.     bra.s    badbpb            ; else no BPB found
  593.                     ; partition not found
  594. bpbnf:    lea    xst,a0            ; a0 = ptr to drive existence table
  595.     move.w    4(sp),d0        ; d0 = dev number
  596.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  597.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  598.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  599.     bra.s    badbpb            ; can't find such a partition
  600.  
  601. bpb5:    move.l    d1,-(sp)        ; start_sector
  602.     move.w    8(sp),-(sp)        ; dev number
  603.     bsr    getbpb            ; getbpb(dev, start_sector)
  604.     addq.l    #6,sp            ; clean up stack
  605.     tst.l    d0            ; getbpb successful?
  606.     bpl.s    retbpb            ; if so, return ptr to bpb
  607.     cmpi.w    #E_CHNG,d0        ; media changed?
  608.     beq    bpbchg            ; if so, restart procedure
  609. badbpb:    moveq    #0,d0            ; return no bpb found
  610. retbpb:    rts
  611.  
  612.  
  613. ;
  614. ;+
  615. ; dosbpb - find the DOS partition that corresponds to the requested
  616. ;       logical drive
  617. ; Passed:
  618. ;    a0 = buffer address for root sector
  619. ;    d1 = number of entries in partition map
  620. ;
  621. ; Assumed:
  622. ;    pbpbs = partition being looked for
  623. ;
  624. ; Returns:
  625. ;    d0.b = 0        if partition not found
  626. ;         = negative #    some kind of error
  627. ;         = positive #    system indicator of the partition
  628. ;    d1.l = starting sector of the partition (if it is found)
  629. ;-
  630. dosbpb:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  631. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  632.     sf    ext            ; not dealing with ext partition
  633.     bsr    fdpart            ; find a partition
  634.     tst.b    d0            ; found any?
  635.     beq.s    dbpba            ; not a valid partition
  636.     cmpi.b    #5,d0            ; extended partition?
  637.     bne.s    dbpb1            ; if not, it's a regular partition
  638.     st    ext            ; else, it's an extended partition
  639.     move.l    #0,extvol        ; offset from start of partition = 0
  640.     move.l    d1,extrt        ; starting sector # of ext partition
  641. dbpbx:    bsr    fdnxt            ; find next logical drive
  642.     tst.b    d0            ; found any?
  643.     beq.s    dbpba            ; no logical drive found
  644.     bmi.s    dbpb2            ; error returned
  645.     cmpi.b    #5,d0            ; extended volume?
  646.     beq.s    dbpbx            ; if so, go find next logical drive
  647. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  648.     bpl.s    dbpb3            ; if not, continue the search
  649. dbpb2:    addq.l    #8,sp            ; else clean up stack
  650.     move.w    #0,bfat            ; assume partition has 12-bit fat
  651.     cmpi.b    #1,d0            ; 12-bit fat?
  652.     beq.s    dbpb22            ; if so, return
  653.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  654. dbpb22:    bra.s    dbpbr            ; and return
  655. dbpb3:    tst.b    ext            ; clun is in ext partition?
  656.     bne.s    dbpbx            ; if so, go find next ext vol
  657. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  658.     adda    #16,a0            ; index to next entry in pmap
  659.     dbra    d1,dbpb0
  660.     moveq    #0,d0            ; partition not found!
  661. dbpbr:    rts
  662.  
  663.     
  664. ;+
  665. ; fdpart - find a DOS partition.
  666. ;
  667. ; Passed:
  668. ;    a0 = address to partition entry
  669. ;
  670. ; Returns:
  671. ;    d0.b = 0        partition is not valid
  672. ;         = positive    #    partition is a valid partition
  673. ;           (this is the system indicator of the partition)
  674. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  675. ;         = starting sector # of extended partition (if d0.b = 5)
  676. ;-
  677. fdpart:    tst.l    12(a0)            ; partition's size?
  678.     beq.s    fdp0            ; if =0, not valid
  679.  
  680.     move.b    4(a0),d0        ; d0 = system indicator
  681.     beq.s    fdpr            ; if =0, not valid
  682.  
  683.     cmpi.b    #4,d0            ; if =4, valid
  684.     beq.s    fdp1
  685.  
  686.     cmpi.b    #1,d0            ; if =1, valid
  687.     beq.s    fdp1
  688.  
  689.     cmpi.b    #5,d0            ; if =5, valid
  690.     beq.s    fdp1
  691.  
  692. fdp0:    moveq    #0,d0            ; else, not valid
  693.     bra.s    fdpr
  694.  
  695. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  696.     ror.w    #8,d1            ; swap hi and lo byte of high word
  697.     swap    d1            ; swap hi and lo word
  698.     ror.w    #8,d1            ; swap hi and lo byte of low word
  699. fdpr:    rts
  700.  
  701.  
  702. ;+
  703. ; fdnxt - find a logical drive in the extended DOS partition
  704. ;
  705. ; Passed:
  706. ;    d0.b = (= 5 if a new extended volume was found)
  707. ;           (= 0 if nxtdrv was successful for last logical drive found)
  708. ;    d1.l = starting sector # of this extended volume
  709. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  710. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  711. ;
  712. ; Assumes:
  713. ;    cpun = current physical unit #
  714. ;    extrt = starting sector # of extended DOS partition
  715. ;    extvol = offset from start of extended DOS partition (in sectors)
  716. ;
  717. ; Returns:
  718. ;    d0.b = 0        no logical drive found
  719. ;         = positive #    valid logical drive found
  720. ;           (this is the system indicator of the logical drive)
  721. ;         = negative #    error occured
  722. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  723. ;         = starting sector # of next extended volume (if d0.b = 5)
  724. ;-
  725. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  726.     bne.s    fdnxt0        ; if not, search for one
  727.     move.w    #1,-(sp)    ; return media change if detected
  728.     move.w    cpun,-(sp)    ; physical unit number
  729.     move.l    _dskbufp,-(sp)    ; buffer to read into
  730.     move.w    #1,-(sp)    ; read in 1 sector
  731.     move.l    d1,-(sp)    ; from beginning of extended volume
  732.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  733.     adda    #14,sp        ; cleanup stack
  734.     tst.w    d0        ; pread successful?
  735.     bne    fdnxtr        ; if so, return
  736.     
  737.     movea.l    _dskbufp,a0    ; else, 
  738.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  739.     bne.s    fdnxtr        ; if not, return no drive found
  740.                 ; (d0 already set by pread)
  741.     adda.w    #DOSPM-16,a0    ; a0 = ptr to 1st entry in log drive map
  742.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  743.  
  744. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  745.     bmi.s    fdnxt1        ; if not, return
  746.  
  747.     adda    #16,a0        ; a0 = ptr to entry to be examined
  748.     tst.l    12(a0)        ; partition size's?
  749.     beq.s    fdnxt0        ; if =0, not valid
  750.  
  751.     move.b    4(a0),d0    ; d0 = system indicator
  752.     beq.s    fdnxt0        ; if =0, not valid
  753.  
  754.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  755.     beq.s    fdnxt0        ; if =0, not valid
  756.     ror.w    #8,d1        ; swap hi and lo byte of high word
  757.     swap    d1        ; swap hi and lo word
  758.     ror.w    #8,d1        ; swap hi and lo byte of low word
  759.  
  760.     cmpi.b    #4,d0        ; if =4,
  761.     beq.s    fdnxt2        ; valid logical drive found
  762.  
  763.     cmpi.b    #1,d0        ; if =1,
  764.     beq.s    fdnxt2        ; valid logical drive found
  765.  
  766.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  767.     bne.s    fdnxt0        ; else, not valid
  768.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  769.     bra.s    fdnxt3
  770.  
  771. fdnxt1:    moveq    #0,d0        ; return no drive found
  772.     bra.s    fdnxtr
  773.  
  774. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  775. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  776. fdnxtr:    rts
  777.  
  778.  
  779. ;
  780. ;+
  781. ; gembpb - find the GEMDOS partition that corresponds to the requested
  782. ;       logical drive.
  783. ; Passed:
  784. ;    a0 = buffer address for root sector
  785. ;    d1 = number of entries in partition map
  786. ;
  787. ; Assumed:
  788. ;    pbpbs = partition being looked for
  789. ;
  790. ; Returns:
  791. ;    d0.b = 0        if partition not found
  792. ;         = negative #    some kind of error
  793. ;         = positive #    system indicator of the partition
  794. ;    d1.l = starting sector of the partition (if it is found)
  795. ;-
  796. gembpb:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  797.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  798.     beq.s    gbpb4            ; if =0, no drive will exist
  799. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  800.     sf    ext            ; not dealing with ext partition
  801.     bsr    fgpart            ; find partitions
  802.     tst.b    d0            ; found any?
  803.     beq.s    gbpba            ; not a valid partition
  804.     cmpi.b    #'X',d0            ; extended partition?
  805.     bne.s    gbpb1            ; if not, it's a regular partition
  806.     st    ext            ; else, it's an extended partition
  807.     move.l    #0,extvol        ; offset from start of partition = 0
  808.     move.l    d1,extrt        ; starting sector # of ext partition
  809. gbpbx:    bsr    fgnxt            ; find next logical drive
  810.     tst.b    d0            ; found any?
  811.     beq.s    gbpba            ; no logical drive found
  812.     bmi.s    gbpb2            ; error returned
  813.     cmpi.b    #'X',d0            ; extended volume?
  814.     beq.s    gbpbx            ; if so, go find next logical drive
  815. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  816.     bpl.s    gbpb3            ; if not, continue the search
  817. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  818.     bra.s    gbpbr            ; and return
  819. gbpb3:    tst.b    ext            ; clun is in ext partition?
  820.     bne.s    gbpbx            ; if so, go find next ext vol
  821. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  822.     adda    #12,a0            ; index to next entry in pmap
  823.     dbra    d1,gbpb0
  824. gbpb4:    moveq    #0,d0            ; partition not found!
  825. gbpbr:    rts
  826.  
  827.  
  828. ;+
  829. ; fgpart - find a GEMDOS partition.
  830. ;
  831. ; Passed:
  832. ;    a0 = address to partition entry
  833. ;
  834. ; Returns:
  835. ;    d0.b = 0        partition is not valid
  836. ;         = positive    #    partition is a valid partition
  837. ;           (this is the first byte in p_id of the partition)
  838. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  839. ;         = starting sector # of extended partition (if d0.b = 'X')
  840. ;-
  841. fgpart:    tst.b    (a0)            ; check the valid partition flag
  842.     beq.s    fgp2            ; if =0, not valid
  843.  
  844.     tst.l    8(a0)            ; partition's size?
  845.     beq.s    fgp2            ; if =0, not valid
  846.  
  847.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  848.     bne.s    fgp0            ; for REGULAR partition
  849.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  850.     bne.s    fgp0
  851.     cmpi.b    #'M',3(a0)
  852.     beq.s    fgp3
  853.  
  854. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  855.     bne.s    fgp1            ; for BIG partition
  856.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  857.     bne.s    fgp1
  858.     cmpi.b    #'M',3(a0)
  859.     beq.s    fgp3
  860.  
  861. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  862.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  863.     cmpi.b    #'G',2(a0)        ; partition
  864.     bne.s    fgp2            ; (ie., partition with
  865.     cmpi.b    #'M',3(a0)        ;  a linked list of
  866.     beq.s    fgp3            ;  logical drives)
  867.  
  868. fgp2:    moveq    #0,d0            ; else, not valid
  869.     bra.s    fgpr
  870.  
  871. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  872.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  873. fgpr:    rts
  874.  
  875.  
  876. ;+
  877. ; fgnxt - find a logical drive in the extended GEMDOS partition
  878. ;
  879. ; Passed:
  880. ;    d0.b = (= 'X' if a new extended volume was found)
  881. ;           (= 0 if nxtdrv was successful for last logical drive found)
  882. ;    d1.l = starting sector # of this extended volume
  883. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  884. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  885. ;
  886. ; Assumes:
  887. ;    cpun = current physical unit #
  888. ;    extrt = starting sector # of extended GEMDOS partition
  889. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  890. ;
  891. ; Returns:
  892. ;    d0.b = 0        no logical drive found
  893. ;         = positive #    valid logical drive found
  894. ;           (this is the first byte of p_id of the logical drive)
  895. ;         = negative #    error occured
  896. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  897. ;         = starting sector # of next extended volume (if d0.b = 'X')
  898. ;-
  899. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  900.     bne.s    fgnxt0        ; if not, search for one
  901.     move.w    #1,-(sp)    ; return media change if detected
  902.     move.w    cpun,-(sp)    ; physical unit number
  903.     move.l    _dskbufp,-(sp)    ; buffer to read into
  904.     move.w    #1,-(sp)    ; read in 1 sector
  905.     move.l    d1,-(sp)    ; from beginning of extended volume
  906.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  907.     adda    #14,sp        ; cleanup stack
  908.     tst.w    d0        ; pread successful?
  909.     bne    fgnxtr        ; if not, return error
  910.  
  911.     movea.l    _dskbufp,a0    ; a0 = ptr to partition map
  912.     adda.w    #HDSIZ+4-12,a0    ; a0 = ptr to 1st entry in log drive map
  913.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  914.  
  915. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  916.     bmi.s    fgnxt3        ; if not, return
  917.  
  918.     adda    #12,a0        ; a0 = ptr to entry to be examined
  919.     tst.l    8(a0)        ; partition size's?
  920.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  921.  
  922.     tst.b    (a0)        ; check the valid partition flag
  923.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  924.  
  925.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  926.  
  927.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  928.     bne.s    fgnxt1        ; for REGULAR partition
  929.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  930.     bne.s    fgnxt1
  931.     cmpi.b    #'M',3(a0)
  932.     beq.s    fgnxt4
  933.  
  934. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  935.     bne.s    fgnxt2        ; for BIG partition
  936.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  937.     bne.s    fgnxt2
  938.     cmpi.b    #'M',3(a0)
  939.     beq.s    fgnxt4
  940.  
  941. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  942.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  943.     cmpi.b    #'G',2(a0)    ; partition
  944.     bne.s    fgnxt3        ; (ie., partition with
  945.     cmpi.b    #'M',3(a0)    ;  a linked list of
  946.     bne.s    fgnxt0        ;  logical drives)
  947.  
  948.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  949.     bra.s    fgnxt5
  950.  
  951. fgnxt3:    moveq    #0,d0        ; return no drive found
  952.     bra.s    fgnxtr
  953.  
  954. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  955. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  956.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  957. fgnxtr:    rts
  958.  
  959.  
  960. ;
  961. ;--------------
  962. ;
  963. ; getbpb(dev, sectorno)
  964. ; WORD dev;        4(sp).w
  965. ; LONG sectorno;    6(sp).l
  966. ;
  967. ; Assume -
  968. ;    cpun contains physical unit number of dev
  969. ;
  970. getbpb:    move.w    #1,-(sp)        ; return media change if detected
  971.     move.w    cpun,-(sp)        ; physical unit
  972.     move.l    _dskbufp,-(sp)        ; buffer
  973.     move.w    #1,-(sp)        ; 1 sector
  974.     move.l    $10(sp),-(sp)        ; sector # of boot sector
  975.     bsr    pread            ; pread(bootsect, 1, buf, phys#, flag)
  976.     adda    #14,sp            ; clean up stack
  977.     tst.w    d0            ; any trouble reading?
  978.     beq.s    getb0            ; if no, go on normally
  979.     cmpi.w    #EREADF,d0        ; was it a read error?
  980.     beq.s    getb9            ; if it is, retry
  981.     cmpi.w    #EDRVNR,d0        ; was it drive not ready?
  982.     bne    getb8            ; if not, return
  983.                     ; else let user retry
  984. getb9:    move.w    4(sp),d1        ; d1 = drive # excluding A: and B:
  985.     bsr    critic
  986.     cmpi.l    #CRITRETRY,d0        ; retry?
  987.     bne    getb7            ; if not, return
  988.     bra.s    getbpb            ; else read again
  989.  
  990. getb0:    movea.l    _dskbufp,a0        ; a0 = ptr to boot sector image
  991.     movea.l    #bpbs,a2        ; a2 = ptr to bpb
  992.  
  993.     move.w    #$0b,d0
  994.     bsr    getlhw
  995.     cmp.w    maxssz,d0        ; is sector size too big?
  996.     bhi    getb7            ; if it is, can't handle it
  997.     move.w    d0,(a2)+        ; =byt/sec
  998.     beq    getb7            ; if =0, bad data
  999.     move.w    d0,d1
  1000.     divu    #512,d0            ; d0.b = ratio log : phys sector size
  1001.     move.w    d0,sizr            ; save the ratio
  1002.  
  1003.     clr.w    d0
  1004.     move.b    $d(a0),d0
  1005.     move.w    d0,(a2)+        ; =sec/cluster
  1006.     beq    getb7            ; if =0, bad data
  1007.  
  1008.     mulu    d1,d0
  1009.     move    d0,(a2)+        ; =byt/cluster
  1010.  
  1011.     move    #$11,d0
  1012.     bsr    getlhw            ; number of directory entries
  1013.     tst    d0            ; num o' entries ?= 0
  1014.     beq    getb7            ; if so, bad data
  1015.     mulu    #32,d0            ; size of each entry
  1016.     divu    d1,d0            ; number of sectors required
  1017.     move.l    d0,d1
  1018.     swap    d1
  1019.     tst    d1
  1020.     beq.s    getb1
  1021.     addq    #1,d0            ; round up
  1022. getb1:    move    d0,(a2)+        ; =rdlen
  1023.     move    d0,d2
  1024.  
  1025.     move    #$16,d0
  1026.     bsr    getlhw
  1027.     move    d0,(a2)+        ; =FATsize
  1028.     beq    getb7            ; if =0, bad data
  1029.     move    d0,d1
  1030.     move    d0,fsiz            ; save FAT size
  1031.  
  1032.     move    #$e,d0
  1033.     bsr    getlhw            ; number of reserved sectors
  1034.     add    d1,d0
  1035.     move    d0,(a2)+        ; =2nd FAT start
  1036.     move    d0,fatrec        ; save 2nd FAT start 
  1037.  
  1038.     add    d1,d0            ; plus size of second fat
  1039.     add    d2,d0            ; plus rdlen
  1040.     move    d0,(a2)+        ; = data start
  1041.     move    d0,d2            ; save start of data
  1042.  
  1043.     move    #$13,d0
  1044.     bsr    getlhw            ; number of sectors on media
  1045.     sub    d2,d0            ; subtract # used by FATs,dir,boot
  1046.     beq    getb7            ; if =0, bad data
  1047.     clr.l    d1
  1048.     move    d0,d1
  1049.     clr    d0
  1050.     move.b    $d(a0),d0        ; number of sectors/cluster
  1051.     divu    d0,d1            ; rounding down
  1052.     move    d1,(a2)+        ; =number of clusters
  1053.     move    bfat,(a2)        ; =flags, 12 or 16 bit fats
  1054.  
  1055.     move.w    sizr,d2            ; d2 = current sector size ratio
  1056.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1057.     move.w    4(sp),d0        ; d0 = drive number
  1058.     move.b    d2,(a1,d0.w)        ; update sector size ratio in table
  1059.  
  1060.     move.w    cpun,d1            ; d1 = physical unit #
  1061.     btst.b    d1,rmbits        ; is unit removable?
  1062.     beq    getb6            ; if not, can skip the fat checksum
  1063.  
  1064.     lea    serno,a1        ; a1 = ptr to table of serial #s
  1065.     mulu.w    #SERLEN,d0        ; dev# * SERLEN to index into table
  1066.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1067.     move.w    #SERLEN-1,d1        ; length of serial # - 1
  1068. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1069.     dbra    d1,getb2
  1070.  
  1071.     lea    fatsum,a2        ; a2 = ptr to FAT check sum table
  1072.     move.w    4(sp),d0        ; d0 = dev number
  1073.     mulu    #FATLEN,d0        ; d0*FATLEN = to index into table
  1074.     adda.l    d0,a2            ; a2 = ptr to FAT check sum tbl of dev
  1075.  
  1076.     move.w    fatrec,d0        ; d0 = log starting sector of 2nd FAT
  1077.     mulu    d2,d0            ; (in 512-byte sectors)
  1078.     movea.l    $6(sp),a1        ; a1 = starting sector of drive
  1079.     adda.l    d0,a1            ; a1 = phys starting sector of 2nd FAT
  1080.  
  1081.     move.w    fsiz,d1            ; d1 = # FAT sectors to read
  1082.     subq.l    #1,d1            ;    = FAT size - 1
  1083.  
  1084. getb3:    move.w    sizr,d2            ; d2 = count per FAT sector
  1085.     subq.w    #1,d2
  1086.      clr.l    temp            ; initialize the sum
  1087. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1088.     move.w    #1,-(sp)        ; return media change if detected
  1089.     move.w    cpun,-(sp)        ; physical unit
  1090.     move.l    a0,-(sp)        ; buffer (in _dskbufp)
  1091.     move.w    #1,-(sp)        ; read 1 phys sector
  1092.     move.l    a1,-(sp)        ; from sector a1
  1093.     bsr    pread            ; pread()
  1094.     adda    #14,sp            ; clean up stack
  1095.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1096.     tst.w    d0            ; pread successful?
  1097.     beq    getb5            ; if so, go on normally
  1098.     cmpi.w    #EREADF,d0        ; read error?
  1099.     beq.s    getba            ; if so, retry
  1100.     cmpi.w    #EDRVNR,d0        ; drive not ready?
  1101.     bne    getb8            ; if not, return
  1102.  
  1103. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1104.     move.w    24(sp),d1        ; d1 = drive # excluding A: and B:
  1105.     bsr    critic            ; critical error handler
  1106.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1107.     cmpi.l    #CRITRETRY,d0        ; retry?
  1108.     beq.s    getb4            ; if so, try again
  1109.     bra    getb7            ; else return
  1110.  
  1111. getb5:    bsr    bsum            ; add up values in the sector
  1112.     addq    #1,a1            ; get ready for next sector
  1113.     dbra    d2,getb4        ; until one logical FAT sector is done
  1114.  
  1115.     bsr    csum            ; find the checksum
  1116.     move.b    d0,(a2)+        ; update checksum for this FAT sector
  1117.     dbra    d1,getb3        ; until all sectors are checked
  1118.  
  1119. getb6:    move.w    $4(sp),d0        ; d0 = dev number
  1120.     lea    mcflgs,a0        ; load address of mcflgs table
  1121.     clr.b    (a0,d0.w)        ; clear mcflg for dev
  1122.  
  1123.     lea    xst,a0            ; a0 = ptr to drive existence table
  1124.     move.b    #2,(a0,d0.w)        ; dev definitely exists
  1125.  
  1126.     lea    fatst,a0        ; a0 = ptr to FAT start sector table
  1127.     asl.w    #1,d0            ; offset = dev# * 2 (tbl of words)
  1128.     move    fatrec,(a0,d0.w)    ; update FAT starting sect#
  1129.  
  1130.     lea    fatend,a0        ; a0 = ptr to FAT end sector table
  1131.     move.w    fatrec,d1        ; d1 = fatend(dev)
  1132.     add.w    fsiz,d1            ;    = fatrec + fsiz - 1
  1133.     subq.w    #1,d1    
  1134.     move.w    d1,(a0,d0.w)        ; fatend(dev) = fatrec + fsiz - 1
  1135.  
  1136.     lea    start,a0        ; a0 = ptr to beginning of start table
  1137.     asl.w    #1,d0            ; offset = dev# * 2 * 2 (tbl of longs)
  1138.     move.l    $6(sp),(a0,d0.w)    ; update starting sect# of dev
  1139.  
  1140.     move.l    #bpbs,d0        ; no errors, return ptr to BPB
  1141.     bra.s    getb8            ; return
  1142.  
  1143. getb7:    moveq    #-1,d0            ; error
  1144. getb8:    rts
  1145.  
  1146.  
  1147. ;+
  1148. ; WORD getlhw(d0=offset)
  1149. ; returns word (low,high) from 0(D0,A0)
  1150. ;-
  1151.  
  1152. getlhw:    move    d1,-(sp)        ; preserve d1
  1153.     move.b    1(a0,d0.w),d1
  1154.     lsl.w    #8,d1
  1155.     move.b    0(a0,d0.w),d1
  1156.     move    d1,d0
  1157.     move    (sp)+,d1
  1158.     rts
  1159.  
  1160.  
  1161. ;+
  1162. ; bsum
  1163. ;
  1164. ; Passed:
  1165. ;    a0 = starting address of buffer to be summed
  1166. ;    temp.l = current sum
  1167. ;
  1168. ; Function:
  1169. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1170. ;    - save the sum in temp.l
  1171. ;
  1172. ; Algorithm for check summing the FAT:
  1173. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1174. ;    - if the sum is non-zero, EOR the high word     (in csum)
  1175. ;      with the low word of the 4-byte result
  1176. ;    - now take this 2-byte result, and EOR its high    (in csum)
  1177. ;      byte with its low byte to get the final 1-byte
  1178. ;      result
  1179. ;-
  1180. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1181.     move.l    temp,d0            ; d0 = current sum
  1182.     move    #127,d1            ; count
  1183. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1184.     dbra    d1,bsum0        ; until all bytes are added
  1185.     move.l    d0,temp            ; temp.l = new sum
  1186.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1187.     rts
  1188.  
  1189.  
  1190. ;+
  1191. ; csum
  1192. ; (a) EOR the high word with the low word of temp.l
  1193. ; (b) then EOR the high byte with the low byte of result of (a)
  1194. ;
  1195. ; Returns:
  1196. ;    d0.b = checksum
  1197. ;-
  1198. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1199.     eor.w    d0,temp            ; exclusive-or low and high word
  1200.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1201.     eor.b    d0,temp            ; exclusive-or low and high byte
  1202.     move.b    temp,d0
  1203.     rts                ; d0.b = checksum
  1204.  
  1205.  
  1206. ;
  1207. ;----------------
  1208. ;
  1209. ;  Read/Write sectors
  1210. ;
  1211. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1212. ;        WORD rw        4(sp).w        ; non-zero -> write
  1213. ;        char buf    6(sp).l
  1214. ;        WORD count    $a(sp).w
  1215. ;        WORD recno    $c(sp).w
  1216. ;        WORD dev    $e(sp).w
  1217. ;        WORD lrecno    $10(sp).l    ; optional
  1218. ;-
  1219.  
  1220. ; stack frame offsets
  1221. xrw    equ    8
  1222. xbuf    equ    10
  1223. xcount    equ    14
  1224. xrecno    equ    16
  1225. xdev    equ    18
  1226. xlrecno    equ    20
  1227.  
  1228. _sasi_rw:
  1229. _ahdi_rw:
  1230.     link    a6,#0            ; create a frame pointer
  1231.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1232.     move.w    xrw(a6),d0        ; r/w and flags word
  1233.     andi.b    #$a,d0            ; phys op?  ignore media change?
  1234.     bne    ahrw1            ; yes, go ahead and do r/w
  1235.                     ; else check for media change
  1236.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1237.     adda.w    xdev(a6),a1        ; a1 = ptr to dev's sector size ratio
  1238.     move.b    (a1),sizr+1        ; sizr = current sector size ratio
  1239.                     ;     (coerced to word)
  1240.     lea    mcflgs,a0        ; a0 = ptr to mcflgs of drive
  1241.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1242.     move.b    (a0),d0            ; d0 = mcflg of dev
  1243.     beq    ahrw1            ; if media definitely not, go do r/w
  1244.  
  1245.     cmpi.b    #2,d0            ; is media definitely changed?
  1246.     beq    retmc            ; if yes, return media has changed
  1247.  
  1248.     sf    mcrw            ; mcrw = FALSE
  1249.     lea    pun,a1            ; a1 = ptr to pun table
  1250.     adda.w    xdev(a6),a1        ; a1 = ptr to pun dev belongs to
  1251.     move.b    (a1),cpun+1        ; cpun = pun of dev
  1252.  
  1253. chkmc:    lea    start,a1        ; a1 = ptr to start table
  1254.     move.w    xdev(a6),d0        ; d0 = drive #
  1255.     add.w    d0,d0            ; d0*2*2 (index into tbl of longs)
  1256.     add.w    d0,d0
  1257.     movea.l    (a1,d0.w),a1        ; a1 = dev starting sector
  1258.  
  1259.     move.w    #1,-(sp)        ; return media change if detected
  1260.     move.w    cpun,-(sp)        ; physical unit number
  1261.     move.l    _dskbufp,-(sp)        ; buffer
  1262.     move.w    #1,-(sp)        ; 1 sector
  1263.     move.l    a1,-(sp)        ; dev starting sector
  1264.     bsr    pread            ; try to read dev's boot sector
  1265.     adda    #14,sp            ; clean up stack
  1266.     tst.w    d0            ; pread successful?
  1267.     beq.s    chkser            ; yes, go check serial number
  1268.  
  1269.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1270.     bne.s    rderr1            ; if not, assume it's read error
  1271.  
  1272. mcchg:    move.b    #1,d0            ; d0.b = 1 (may be changed)
  1273.     move.w    xdev(a6),d1        ; d1.w = drive # excluding A: and B:
  1274.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1275.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1276.     bra.s    chkmc            ; then try again
  1277.  
  1278. rderr1:    move.w    xdev(a6),d1        ; device number
  1279.     bsr    critic            ; call critical error handler
  1280.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1281.     beq.s    chkmc            ; if yes, go back and try it
  1282.     bra    ahrw7            ; else return
  1283.  
  1284. chkser:    lea    serno,a1        ; a1 = ptr to serial #s table
  1285.     move.w    xdev(a6),d0        ; d0 = dev number
  1286.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1287.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1288.  
  1289.     move.l    _dskbufp,a2        ; a2 = ptr to buffer
  1290.     addq.w    #8,a2            ; a2 = ptr to serial # read
  1291.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1292. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1293.     bne    ismc            ; no, media has changed
  1294.     dbra    d0,cmpser        ; compare next byte of serial #
  1295.                     ; serial # hasn't changed, try FAT
  1296.     move.w    xdev(a6),d0        ; d0 = dev number
  1297.     lea    fatsum,a1        ; a1 = ptr to fat checksum table
  1298.     move.w    #FATLEN,d1        ; d1.w = index into table
  1299.     mulu    d0,d1
  1300.     adda.l    d1,a1            ; a1 = ptr to fat checksum of dev
  1301.  
  1302.     add.w    d0,d0            ; d0*2 = index into table of words
  1303.     lea    fatst,a2        ; a2 = ptr to FAT start table
  1304.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1305.  
  1306.     lea    fatend,a2        ; a2 = ptr to FAT end table
  1307.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1308.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1309.  
  1310.     lea    start,a2        ; a2 = ptr to start table
  1311.     add.w    d0,d0            ; d0*2*2 = index into table of longs
  1312.     movea.l    (a2,d0.w),a2        ; a2 = start sector of dev
  1313.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1314.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1315.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1316.  
  1317.     movea.l    _dskbufp,a0        ; a0 = ptr to buffer
  1318. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1319.     subq.w    #1,d2            ; d2 - 1 = counter
  1320.     clr.l    temp            ; initialize sum
  1321. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a1, a2
  1322.     move.w    #1,-(sp)        ; return media change if detected
  1323.     move.w    cpun,-(sp)        ; physical unit number
  1324.     move.l    a0,-(sp)        ; buffer
  1325.     move.w    #1,-(sp)        ; 1 sector
  1326.     move.l    a2,-(sp)        ; at sector a2
  1327.     bsr    pread            ; try to read this FAT sector
  1328.     adda    #14,sp            ; clean up stack
  1329.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, a0, a1, a2
  1330.     tst.w    d0            ; pread successful?
  1331.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1332.                     ; else check if it's media change
  1333.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1334.     beq    mcchg            ; if so, go test media change again
  1335.                     ; else assume it's read error
  1336.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1337.     move.w    xdev(a6),d1        ; drive number
  1338.     bsr    critic
  1339.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1340.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1341.     beq.s    cfat0            ; if yes, go back and try it
  1342.     bra    ahrw7            ; else return
  1343.  
  1344. chkfat:    bsr    bsum            ; if ok, sum the sector
  1345.     addq    #1,a2            ; ready for try next sector
  1346.     dbra    d2,cfat0        ; until one FAT sector is summed
  1347.  
  1348.     bsr    csum            ; find the checksum
  1349.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1350.     bne    ismc            ; if no match, media has changed
  1351.     dbra    d1,cmpfat        ; until all sectors are checked
  1352.  
  1353.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1354.     adda.w    xdev(a6),a0        ; a0 = ptr to mcflg of drive
  1355.     clr.b    (a0)            ; clear mcflg for dev
  1356.  
  1357. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1358.     beq    ahrw6            ; if =0, done
  1359.  
  1360.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1361.     bne.s    ahrw9            ; if not, we have a word record #
  1362.     move.l    xlrecno(a6),a1        ; a1.l = start record #
  1363.     bra.s    ahrwa
  1364. ahrw9:    moveq    #0,d0            ; coerce to long
  1365.     move.w    xrecno(a6),d0        ; d0.l = recno
  1366.     movea.l    d0,a1            ; a1.l = start record #
  1367.  
  1368. ahrwa:    move.l    a1,strec        ; save first sector to r/w
  1369.     moveq    #0,d1            ; coerce to long
  1370.     move.w    xcount(a6),d1        ; d1.l = #sectors to r/w
  1371.     adda.l    d1,a1            ; a1.l = last sector to r/w
  1372.     subq.w    #1,a1            ;      = first sector + count - 1
  1373.     move.l    a1,endrec        ; save last sector to r/w
  1374.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1375.  
  1376.     move.l    strec,d1        ; d1.l = starting sector to r/w
  1377.     moveq    #0,d2            ; clear d2
  1378.     move.w    xcount(a6),d2        ; d2.l = # sectors to r/w
  1379.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1380.     bne.s    ahrwb            ; if so, go on
  1381.                     ; else log -> phys sector mapping
  1382.     mulu    sizr,d1            ; d1.l = phys start sector to r/w
  1383.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1384.  
  1385. ahrwb:    move.l    xbuf(a6),a1        ; a1.l = buffer addr to r/w
  1386.     cmpi.l    #MAXSECTORS,d2        ; more than one DMAfull?
  1387.     bgt.s    ahrwc            ; if so, only do one DMAfull
  1388.     move.w    d2,xcount(a6)        ; else xcount(a6) = # sects requested
  1389.     bra.s    ahrw2
  1390. ahrwc:    move.w    #MAXSECTORS,xcount(a6)    ; xcount(a6) = 1 DMAfull of sects
  1391. ahrw2:    btst    #0,xbuf+3(a6)        ; an odd boundary?
  1392.     beq.s    ahrw4            ; no, so do normally
  1393.  
  1394.     cmpi.w    #2,xcount(a6)        ; can only do 2 at a time tops this way
  1395.     ble.s    ahrw3
  1396.     move.w    #2,xcount(a6)
  1397.  
  1398. ahrw3:    move.l    _dskbufp,a1        ; use the bios buffer for this transfer
  1399.  
  1400.     btst    #0,xrw+1(a6)        ; is this a write?
  1401.     beq.s    ahrw4            ; no, so go fill buffer from disk
  1402.  
  1403.     movea.l    xbuf(a6),a2        ; source (a1.l = dest)
  1404.     move.w    xcount(a6),-(sp)    ; # sectors to be moved
  1405.     bsr    smove            ; move sectors from a2 to a1
  1406.     addq.l    #2,sp            ; clean up stack
  1407.  
  1408. ahrw4:    movem.l    d1-d2,-(sp)        ; save total count and start sector
  1409.     move.w    xdev(a6),-(sp)
  1410.     move.l    d1,-(sp)
  1411.     move.w    xcount(a6),-(sp)    ; count
  1412.     move.l    a1,-(sp)        ; buffer
  1413.     move.w    xrw(a6),-(sp)
  1414.     bsr    _do_rw
  1415.     adda    #14,sp
  1416.     movem.l    (sp)+,d1-d2        ; restore total count and start sector
  1417.     tst.l    d0            ; any errors there?
  1418.     beq.s    ahrw8            ; no, go on normally
  1419.  
  1420.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1421.     bne    ahrw7            ; if not, give up
  1422.     st    mcrw            ; else it's mc returned when r/w
  1423.     bra    mcchg            ; and go check if media has changed
  1424.  
  1425. ahrw8:    btst    #0,xbuf+3(a6)        ; on odd boundary?
  1426.     beq.s    ahrw5            ; if not, go on normally
  1427.     btst    #0,xrw+1(a6)        ; was it a read?
  1428.     bne.s    ahrw5            ; if it wasn't, go on normally
  1429.                     ; else
  1430.     movea.l    xbuf(a6),a1        ; must move data read to desired dest
  1431.     movea.l    _dskbufp,a2        ; from dskbuf
  1432.     move.w    xcount(a6),-(sp)    ; # of sectors to move
  1433.     bsr    smove
  1434.     addq.l    #2,sp            ; clean up stack
  1435.  
  1436. ahrw5:    moveq    #0,d0            ; clear d0
  1437.     move.w    xcount(a6),d0        ; #sectors we did
  1438.     sub.l    d0,d2            ; #sectors left to do
  1439.     add.l    d0,d1            ; next starting sector to r/w
  1440.     asl.l    #8,d0            ; d0 = #bytes we did
  1441.     add.l    d0,d0            ;    = #sectors * 512
  1442.     add.l    d0,xbuf(a6)        ; buf += (sectors_done * sector size)
  1443.     tst.l    d2            ; anything left to r/w?
  1444.     bne    ahrwb            ; if so, continue
  1445.                     ; check if wrote to boot sector
  1446. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1447.     btst    #0,d0            ; was it a write?
  1448.     beq    ahrw6            ; if not, done
  1449.     btst    #3,d0            ; was it a physical operation?
  1450.     bne    ahrw6            ; if it was, done
  1451.     btst    #1,d0            ; ignore media change?
  1452.     bne.s    wrfat            ; if so, update FAT chksums if appl.
  1453.     tst.l    strec            ; wrote to boot sector?
  1454.     bne.s    wrfat            ; if not, update FAT chksums if appl.
  1455.     lea    mcflgs,a0        ; else, a0 = ptr to mcflgs table
  1456.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1457.     move.b    #2,(a0)            ; assume medium has changed
  1458.  
  1459. wrfat:    moveq    #0,d0            ; clear d0
  1460.     move.b    cpun+1,d0        ; d0.b = pun of dev
  1461.     btst.b    d0,rmbits        ; is drive removable?
  1462.     beq    ahrw6            ; if not, done
  1463.                     ; else check if wrote to FATs
  1464.     lea    fatend,a0        ; a0 = ptr to fatend table
  1465.     move.w    xdev(a6),d0        ; d0 = device number
  1466.     add.w    d0,d0            ; d0*2 = index into table of words
  1467.     moveq    #0,d1            ; coerce to long
  1468.     move.w    (a0,d0.w),d1        ; d1 = last FAT's ending sector
  1469.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1470.     blt    ahrw6            ; if so, done
  1471.  
  1472.     lea    fatst,a0        ; a0 = ptr to fatst table
  1473.     moveq    #0,d2            ; coerce to long
  1474.     move.w    (a0,d0.w),d2        ; d2 = last FAT's starting sector
  1475.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1476.     bgt    ahrw6            ; if so, done
  1477.                     ; else update FAT sector checksums
  1478.     move.l    stbuf,a0        ; a0 = ptr to buffer w/ written data
  1479.     lea    fatsum,a1        ; a1 = ptr to start of fatsum table
  1480.     move.w    xdev(a6),d0        ; d0 = dev number
  1481.     mulu.w    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1482.     adda.l    d0,a1            ; a1 = ptr to dev's first FAT chksum
  1483.     move.l    strec,d0        ; d0 = first sector wrote to
  1484.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1485.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1486.                     ;     no adjustments needed
  1487.      blt.s    wrfat1            ; if strec < start(last FAT)
  1488.                     ;     begin from start(last FAT)
  1489.     move.l    strec,d2        ; else begin from strec
  1490.     adda.l    d0,a1            ; a1 = ptr to fatsum to be updated
  1491.     bra.s    wrfat2
  1492.  
  1493. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1494.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1495.     add.l    d0,d0
  1496.     adda.l    d0,a0            ; a0 = pt to addr of buf for update
  1497.  
  1498. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1499.     ble.s    wrfat3            ;     stop at end(last FAT)
  1500.     move.l    endrec,d1        ; else stop at endrec
  1501.  
  1502. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1503. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1504.     subq.w    #1,d2            ; dbra likes one less
  1505.     clr.l    temp            ; initialize sum
  1506. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1507.     adda.l    #512,a0            ; point to next 512 bytes
  1508.     dbra    d2,wrfat5        ; until one logical sector is done
  1509.     bsr    csum            ; obtain checksum
  1510.     move.b    d0,(a1)+        ; record new fat checksum
  1511.     dbra    d1,wrfat4        ; do until all are updated
  1512.  
  1513. ahrw6:    clr.l    d0            ; got here with no errors!
  1514.     bra.s    ahrw7
  1515.  
  1516. ismc:    tst.b    mcrw            ; media change returned by r/w?
  1517.     beq    onemc            ; no, only dev has changed
  1518.     move.b    #2,d0            ; d0.b = value to set to
  1519.     move.w    xdev(a6),d1        ; d1.w = dev number
  1520.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1521.     bsr    s_mc_xst        ; set mcflgs and xst flags for devs
  1522.     bra.s    retmc            ; return media change detected
  1523.  
  1524. onemc:    lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1525.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1526.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1527.     lea    xst,a0            ; a0 = ptr to drive existence table
  1528.     adda.w    xdev(a6),a0        ; a0 = ptr to xst flag of dev
  1529.     move.b    #2,(a0)            ; assume dev exists
  1530.  
  1531. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1532. ahrw7:    unlk    a6
  1533.     rts
  1534.  
  1535.  
  1536. ;----------------
  1537. ;
  1538. ;  Copy unaligned sectors
  1539. ;  (this is *supposed* to be slow!)
  1540. ;
  1541. ;    Passed:    d2.w    = # of sectors (known to be 1 or 2)
  1542. ;        a2    -> source sector
  1543. ;        a1    -> dest buffer (oddly aligned)
  1544. ;
  1545. smove:    move.w    4(sp),d0        ; d0 = # 512-byte sectors to move
  1546.     asl.w    #8,d0            ; d0 * 512 = # bytes to move
  1547.     asl.w    #1,d0
  1548.     subq.w    #1,d0            ; dbra likes one less
  1549. smove1:    move.b    (a2)+,(a1)+
  1550.     dbra    d0,smove1
  1551.     rts
  1552.  
  1553.  
  1554. ;
  1555. ;+
  1556. ; _do_rw - called to read/write no more than 128K to an even boundary
  1557. ;
  1558. ; Passed:    dev    $10(sp).W
  1559. ;        recno    $c(sp).L
  1560. ;        count    $a(sp).W
  1561. ;        buf    6(sp).L
  1562. ;        rw    4(sp).W        ; non-zero -> write
  1563. ;
  1564. ;-
  1565. _do_rw:
  1566.     move.w    d3,-(sp)        ; preserve d3
  1567.  
  1568. sasrw0:    move.w    _retries,retrycnt    ; setup retry counter
  1569.  
  1570.     move.w    6(sp),d3        ; rw
  1571.     btst    #2,d3            ; are retries disabled?
  1572.     beq.s    sasrw1            ; no, act normally
  1573.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1574.  
  1575. sasrw1:    lea    2(sp),a1        ; frame pointer
  1576.     move.l    $c(a1),d0        ; sect.L
  1577.     move.w    4(a1),d3        ; rw
  1578.  
  1579.     btst    #3,d3            ; physical unit operation
  1580.     beq.s    sasrw2            ; no, so do log->phys mapping
  1581.  
  1582.     move    $10(a1),cpun        ; get unit number
  1583.     bra.s    sasrw3            ; and use that as the physical unit
  1584.  
  1585. sasrw2:    clr    d2            ; coerce byte to word
  1586.     move.w    $10(a1),d1        ; get device
  1587.      lea    pun,a2
  1588.     move.b    (a2,d1.w),cpun+1    ; get physical unit number
  1589. sasrw3:    move.w    cpun,-(sp)        ; dev
  1590.     move.l    6(a1),-(sp)        ; buf
  1591.     move.w    $a(a1),-(sp)        ; count
  1592.  
  1593.     btst    #3,d3            ; physical operation?
  1594.     bne.s    sasrw4            ; yes, so no offset
  1595.  
  1596.     add.w    d1,d1            ; d1*2*2 = index into table of longs
  1597.     add.w    d1,d1
  1598.     lea    start,a2
  1599.     add.l    (a2,d1.w),d0        ; adjust sector number
  1600.  
  1601. sasrw4:    move.l    d0,-(sp)        ; sect
  1602.     btst    #0,d3            ; read or write?
  1603.     bne.s    sasrw5            ; (write)
  1604.     bsr    _hread            ; read sectors
  1605.     bra.s    sasrw6
  1606. sasrw5:    bsr    _hwrite            ; write sectors
  1607. sasrw6:    adda    #12,sp            ; (cleanup stack)
  1608.     tst.l    d0            ; errors?
  1609.     beq    sasrwr            ; no -- success
  1610.  
  1611.     bsr    errcode            ; find error code
  1612.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  1613.     beq.s    sasrw7
  1614.     cmpi.b    #WRTPRTD,d0        ; write on write-protected media?
  1615.     beq.s    sasrw9
  1616.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  1617.     beq.s    sasrwe
  1618.  
  1619.     subq.w    #1,retrycnt        ; drop retry count and retry
  1620.     bpl    sasrw1
  1621.  
  1622.     move    6(sp),d1        ; get r/w and flags word
  1623.     move.l    #EREADF,d0        ; read error code
  1624.     btst    #0,d1            ; is it a write?
  1625.     beq.s    sasrwa
  1626.     move.l    #EWRITF,d0        ; write error code
  1627.     bra.s    sasrwa
  1628.  
  1629. sasrw7:    move.w    6(sp),d1        ; get r/w and flags word
  1630.     andi.b    #$a,d1            ; no media change/physical operation?
  1631.     beq.s    sasrw8            ; if not, return media change
  1632.     move.b    #1,d0            ; d0.b = medium may have changed
  1633.     move.w    $12(a6),d1        ; d1.w = dev number
  1634.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1635.     bsr    s_mc_xst        ; set mcflgs and xst flags for dev
  1636.     bra    sasrw0            ; start all over
  1637.     
  1638. sasrw8:    move.l    #E_CHNG,d0        ; media change detected
  1639.     bra.s    sasrwr            ; return
  1640.  
  1641. sasrw9:    move.l    #EWRPRO,d0        ; write on write-protected media
  1642.     bra.s    sasrwf
  1643.  
  1644. sasrwe:    move.l    #EDRVNR,d0        ; drive not ready
  1645. sasrwf:    move.w    6(sp),d1        ; get r/w and flags word
  1646.  
  1647. sasrwa:    btst    #3,d1            ; is this a physical operation?
  1648.     beq.s    sasrwc            ; no, call critical error handler
  1649.                     ; else find 1st drive of current unit
  1650.     lea    pun,a0            ; a0 = ptr to pun table
  1651.     move.w    cpun,d2            ; d1 = current pun
  1652.     moveq    #0,d1            ; d2 = index into pun table
  1653. sasrwb:    cmp.b    (a0,d1.w),d2        ; 1st drive of unit?
  1654.     beq.s    sasrwd            ; if so, get drive number 
  1655.     addq.w    #1,d1            ; else, get next drive number
  1656.     cmpi.w    #MAXUNITS,d1        ; reach end of pun table?
  1657.     bge.s    sasrwr            ; if so, forget it
  1658.     bra.s    sasrwb            ; else try this next drive
  1659.  
  1660. sasrwc:    move.w    $12(sp),d1        ; d1 = drive number
  1661. sasrwd:    bsr    critic
  1662.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1663.     beq    sasrw0            ; if yes, go retry
  1664.  
  1665. sasrwr:    move.w    (sp)+,d3        ; remember to restore d3
  1666.     rts
  1667.  
  1668.  
  1669. ;
  1670. ;----------------
  1671. ;
  1672. ; Check for media change on hard disk
  1673. ; Synopsis:    _sasi_mediach(dev)
  1674. ;        WORD dev;        4(sp).w
  1675. ;
  1676. ; Returns:    0L - media definitely has not changed
  1677. ;        1L - media _may_ have changed
  1678. ;        2L - media definitely has changed
  1679. ;
  1680. ; Uses:        d0, d1, a0, a1
  1681. ;
  1682. ; Comments:
  1683. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1684. ;            If _sasi_mediach() was called less than 1 s
  1685. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1686. ;            not changed then, assume medium still has not 
  1687. ;            changed.
  1688. ;
  1689. _sasi_mediach:
  1690.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1691.     move.w    4(sp),d1        ; d1 = current drive
  1692.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1693.     moveq    #0,d0            ; d0 = mcflg for current drive
  1694.     move.b    (a0,d1.w),d0    
  1695.     tst.b    d0            ; has medium changed?
  1696.     bne.s    decided            ; if yes or maybe, return result
  1697.                     ; else verify that it has not
  1698.     move.l    lastmdctm,d2        ; time media change was last called
  1699.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1700.     bcc.s    decided            ;    assume medium not changed
  1701.  
  1702.     lea    pun,a1            ; ptr to beginning of pun table
  1703.     clr.w    d2            ; coerce byte to word
  1704.     move.b    (a1,d1.w),d2        ; d2 = pun current drive belongs to
  1705.  
  1706.     btst.b    d2,rmbits        ; is pun removable?
  1707.     beq.s    notchngd        ; if not, medium has not changed
  1708.  
  1709.     movem.w    d1-d2,-(sp)        ; else save registers
  1710.     move.w    d2,-(sp)        ; physical unit number
  1711.     bsr    testunit        ; verify by doing test unit ready
  1712.     addq.l    #2,sp
  1713.     movem.w    (sp)+,d1-d2        ; restore registers
  1714.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  1715.     addi.l    #200,lastmdctm        ; 
  1716.     tst.w    d0            ; return good status?
  1717.     beq.s    notchngd        ; if yes, return medium not changed
  1718.     moveq    #1,d0            ; else return medium may have changed
  1719.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  1720.     bra.s    decided
  1721. notchngd:
  1722.     moveq    #0,d0            ; return medium has not changed
  1723. decided:
  1724.     rts
  1725.  
  1726.  
  1727. ;+
  1728. ; s_mc_xst - set mcflgs and drive existence flags 
  1729. ;         for drives belonging to a physical unit 
  1730. ;         to value passed
  1731. ;
  1732. ; Passed:    d0.b - value to set to
  1733. ;         d1.w - dev number
  1734. ;        d2.b - physical unit #
  1735. ;-
  1736. s_mc_xst:
  1737.     movem.l    a0-a2,-(sp)    ; save registers
  1738.     move.w    d1,-(sp)    ; save dev number
  1739.     lea    mcflgs,a0    ; a0 = ptr to mcflgs table
  1740.     lea    pun,a1        ; a1 = ptr to pun table
  1741.     lea    xst,a2        ; a2 = ptr to drive existence table
  1742. back:    cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1743.     bne.s    oppdir        ; if not, try opposition direction
  1744.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1745.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1746.     dbra    d1,back        ; try next one in backward direction
  1747. oppdir:    move.w    (sp)+,d1    ; get device number again
  1748. forth:    addq.w    #1,d1        ; try next one in forward direction
  1749.     cmp.w    #MAXUNITS,d1    ; all units checked?
  1750.     bge.s    setr        ; if yes, get ready to return
  1751.     cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1752.     bne.s    setr        ; if not, get ready to return
  1753.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1754.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1755.     bra.s    forth        ; continue to search
  1756. setr:    movem.l    (sp)+,a0-a2    ; restore registers
  1757.     rts
  1758.  
  1759.  
  1760. ;
  1761. ;--------------------- Low-Level Driver -------------------
  1762.  
  1763. ;----------------
  1764. ;
  1765. ;  Hardware definitions
  1766. ;
  1767. wdc        equ    $ffff8604
  1768. wdl        equ    $ffff8606
  1769. wdcwdl        equ    wdc        ; used for long writes
  1770. xwdl        equ    wdl-wdc        ; offset from wdc to wdl
  1771.  
  1772. dmahi        equ    $ffff8609
  1773. dmamid        equ    dmahi+2
  1774. dmalow        equ    dmamid+2
  1775. gpip        equ    $fffffa01
  1776.  
  1777.  
  1778. ;----------------
  1779. ;
  1780. ;  Tunable (delay) values
  1781. ;
  1782. ltimeout        equ    600        ; long-timeout (3 S)
  1783. stimeout        equ    20        ; short-timeout (100 mS)
  1784.  
  1785.  
  1786. ;----------------
  1787. ;
  1788. ; LONG _qdone() - Wait for command byte handshake
  1789. ; LONG _fdone() - Wait for operation complete
  1790. ; Passed:    nothing
  1791. ;
  1792. ; Returns:    EQ: no timeout
  1793. ;        MI: timeout condition
  1794. ;
  1795. ; Uses:        D0
  1796. ;
  1797. ; each pass through the loop takes 6.75 uS
  1798. ;-
  1799. _fdone:    move.l    _hz_200,d0
  1800.     add.l    #ltimeout,d0
  1801.     bra.s    qd1
  1802.  
  1803. _qdone:    move.l    _hz_200,d0
  1804.     add.l    #stimeout,d0
  1805.  
  1806. qd1:    cmp.l    _hz_200,d0        ; timeout?
  1807.     bcs.s    qdq            ; (i give up, return NE)
  1808.     btst    #5,gpip            ; interrupt?
  1809.     bne.s    qd1            ; (not yet)
  1810.  
  1811.     moveq    #0,d0            ; return EQ (no timeout)
  1812.     rts
  1813.  
  1814. qdq:    moveq    #-1,d0
  1815.     rts
  1816.  
  1817.  
  1818. ;----------------
  1819. ;
  1820. ; Wait for end of SASI command
  1821. ;
  1822. ; Passed:    d0 value to be written to wdl
  1823. ;
  1824. ; Returns:    EQ: success (error code in D0.W)
  1825. ;        MI: timeout (-1 in D0.W)
  1826. ;        NE: failure (SASI error code in D0.W)
  1827. ;
  1828. ; Uses:        d0,d1
  1829. ;-
  1830. _endcmd: move    d0,d1            ; preserve wdl value
  1831.  
  1832.     bsr    _fdone            ; wait for operation complete
  1833.     bmi.s    endce            ; (timed-out, so complain)
  1834.  
  1835.     move.w    d1,wdl
  1836.     move.w    wdc,d0            ; get the result
  1837.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  1838.                     ; do a ReadSense command to learn more
  1839. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  1840.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  1841.     rts                
  1842.  
  1843.  
  1844. ;+
  1845. ;  Handle command timeout;
  1846. ;  Unlock DMA chip and return completion status;
  1847. ;-
  1848. _hto:    moveq    #-1,d0        ; indicate timeout
  1849. _hdone:    move.w    #$80,wdl    ; Landon's code seems to presume we
  1850.     tst.w    wdc
  1851.     clr    flock        ; NOW, signal that we are done
  1852.     rts
  1853.  
  1854.  
  1855. ;+
  1856. ; delay()
  1857. ;    5 - 10ms kludge delay for message byte sent back by controller.
  1858. ;-
  1859. _delay:    move.l    lastacstm,d0        ; d0 = controller last accessed time
  1860. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  1861.     bcc.s    wait            ;    wait()
  1862.     rts
  1863.  
  1864.  
  1865. ;
  1866. ;-----------------
  1867. ;
  1868. ; _hread(sectno, count, buf, dev)
  1869. ; LONG sectno;         4(sp)
  1870. ; WORD count;         8(sp)
  1871. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1872. ; WORD dev;        $e(sp)
  1873. ;
  1874. ; Returns:    -1 on timeout
  1875. ;        0 on success
  1876. ;        nonzero on error
  1877. ;
  1878. ;-
  1879. _hread:    bsr    _delay
  1880.     movea.l    #wdc,a0            ; pointer to DMA chip
  1881.     st    flock            ; lock FIFO
  1882.  
  1883.     move    #$88,xwdl(a0)    ;wdl
  1884.     clr.l    d0
  1885.     move.w    $0e(sp),d0        ; get unit number
  1886.     lsl.w    #5,d0
  1887.     swap    d0
  1888.     ori.l    #$0008008a,d0        ; 08 wdc, 8a wdl
  1889.     move.l    d0,(a0)     ;wdcwdl
  1890.  
  1891.     move.l    $a(sp),-(sp)        ; set DMA address
  1892.     bsr    _setdma
  1893.     addq.l    #4,sp
  1894.  
  1895.     bsr    _setss            ; set sector and size
  1896.     bmi    _hto
  1897.  
  1898.     move.w    #$190,xwdl(a0)    ;wdl
  1899.     move.w    #$90,xwdl(a0)    ;wdl
  1900.     move.w    8(sp),(a0)     ;wdc    ; write sector count to DMA chip
  1901.     move.w    #$8a,xwdl(a0)    ;wdl
  1902.     move.l    #$00000000,(a0) ;wdcwdl    ; control byte  0 wdc 0 wdl
  1903.  
  1904.     move.w    #$8a,d0
  1905.     bsr    _endcmd
  1906.  
  1907. hrx:    bra    _hdone            ; cleanup after IRQ
  1908.  
  1909.  
  1910. ;
  1911. ;----------------
  1912. ;
  1913. ; _hwrite(sectno, count, buf, dev)
  1914. ; LONG sectno;         4(sp)
  1915. ; WORD count;         8(sp)
  1916. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1917. ; WORD dev;        $e(sp)
  1918. ;
  1919. ;-
  1920. _hwrite:
  1921.     bsr    _delay
  1922.     movea.l    #wdc,a0            ; pointer to DMA chip
  1923.     st    flock            ; lock FIFO
  1924.  
  1925.     move.l    $a(sp),-(sp)        ; set DMA address
  1926.     bsr    _setdma
  1927.     addq.l    #4,sp
  1928.  
  1929.     move.w    #$88,xwdl(a0)    ;wdl
  1930.     clr.l    d0
  1931.     move.w    $0e(sp),d0        ; get unit number
  1932.     lsl.w    #5,d0
  1933.     swap    d0
  1934.     ori.l    #$000a008a,d0        ; 0a wdc 8a wdl
  1935.     move.l    d0,(a0)     ;wdcwdl
  1936.  
  1937.     bsr    _setss
  1938.     bmi    _hto
  1939.  
  1940.     move.w    #$90,xwdl(a0)    ;wdl
  1941.     move.w    #$190,xwdl(a0)    ;wdl
  1942.     move.w    8(sp),(a0)     ;wdc    ; sector count for DMA chip's benefit
  1943.     move.w    #$18a,xwdl(a0)
  1944.     move.l    #$00000100,(a0) ;wdcwdl
  1945.  
  1946.     move.w    #$18a,d0
  1947.     bsr    _endcmd
  1948.  
  1949. hwx:    bra    _hdone            ; cleanup after IRQ
  1950.  
  1951.  
  1952. ;
  1953. ;----------------
  1954. ;
  1955. ; Set DMA address
  1956. ;
  1957. ; void _setdma(addr)
  1958. ; LONG addr;
  1959. ;-
  1960. _setdma:
  1961.     move.b    7(sp),dmalow
  1962.     move.b    6(sp),dmamid
  1963.     move.b    5(sp),dmahi
  1964.     rts
  1965.  
  1966.  
  1967. ;----------------
  1968. ;
  1969. ; Set sector number and number of sectors
  1970. ;
  1971. _setss:    move.w    #$8a,xwdl(a0)
  1972.  
  1973.     bsr    _qdone            ; wait for controller to take command
  1974.     bmi    setsse
  1975.  
  1976.     move.b    9(sp),d0        ; construct sector#
  1977.     swap    d0
  1978.     move.w    #$008a,d0
  1979.     move.l    d0,(a0)     ;wdcwdl    ; write MSB sector# + devno
  1980.     bsr    _qdone
  1981.     bmi    setsse
  1982.  
  1983.     move.b    10(sp),d0        ; write MidSB sector#
  1984.     swap    d0
  1985.     move.w    #$008a,d0
  1986.     move.l    d0,(a0)     ;wdcwdl
  1987.     bsr    _qdone
  1988.     bmi    setsse
  1989.  
  1990.     move.b    11(sp),d0        ; write LSB sector#
  1991.     swap    d0
  1992.     move.w    #$008a,d0
  1993.     move.l    d0,(a0)     ;wdcwdl
  1994.     bsr    _qdone
  1995.     bmi    setsse
  1996.  
  1997.     move.w    12(sp),d0        ; write sector count
  1998.     swap    d0
  1999.     move.w    #$008a,d0
  2000.     move.l    d0,(a0)     ;wdcwdl
  2001.     bsr    _qdone
  2002.  
  2003. setsse:    rts
  2004.  
  2005.  
  2006. ;
  2007. ;----------------
  2008. ;
  2009. ;  _inquiry - get device-specific parameters
  2010. ;
  2011. ;    Synopsis:    LONG _inquiry(physunit#, parms)
  2012. ;        WORD physunit#;            4(sp).W
  2013. ;        char *parms;            6(sp).L
  2014. ;
  2015. ; Old driver uses these two lines which do NOT do 
  2016. ; "d0 = (dev << 5) << 16" because the hi word of
  2017. ; D0 before the swap (lo word after) is garbage.
  2018. ;    lsl.b    #5,d0
  2019. ;    swap    d0
  2020. ;-
  2021. _inquiry:
  2022.     bsr    _delay
  2023.     st    flock            ; lock FIFO
  2024.     move.l    6(sp),-(sp)        ; -> parameter block address
  2025.     bsr    _setdma            ; set DMA there
  2026.     addq.l    #4,sp
  2027.     movea.l    #wdc,a0            ; pointer to DMA chip
  2028. ; write command and phyunit#
  2029.     move.w    #$88,xwdl(a0)    ;wdl
  2030.     move.w    4(sp),d0        ; d0 = (physunit# << 5) << 16
  2031.     moveq    #21,d1
  2032.     lsl.l    d1,d0            
  2033.     or.l    #$0012008a,d0        ; write physunit# + Inquiry + FIFO bits
  2034.     move.l    d0,(a0)        ;wdcwdl    ; inquiry+physunit# wdc 8a wdl (byte 0)
  2035.     bsr    _qdone
  2036.     bmi    inq
  2037.  
  2038.     move.l    #$8a,d1            ; d1 = byte to be sent
  2039.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2040.     bsr    _qdone
  2041.     bmi    inq
  2042.  
  2043.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2044.     bsr    _qdone
  2045.     bmi    inq
  2046.  
  2047.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2048.     bsr    _qdone
  2049.     bmi    inq
  2050.  
  2051.     move.l    #$0010008a,(a0)    ;wdcwdl    ; 16 byte of parameters (byte 4)
  2052.     bsr    _qdone
  2053.     bmi    inq
  2054.  
  2055.     move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2056.     move.w    #$90,xwdl(a0)    ;wdl
  2057.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2058.     move.w    #$8a,xwdl(a0)    ;wdl
  2059.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2060.     move.w    #$8a,d0            ; wdl value
  2061.     bsr    _endcmd            ; wait for command completion
  2062. inq:    bra    _hdone
  2063.  
  2064.  
  2065. ;
  2066. ;---------------
  2067. ;
  2068. ;  LONG _rq_sense() - get non-extended sense data from target
  2069. ;  LONG _rq_xsense() - get extended sense data from target
  2070. ;
  2071. ;  Passed:
  2072. ;    WORD physunit#;            4(sp).W        $6(sp).w
  2073. ;    char data[];            6(sp).L        $8(sp).l
  2074. ;
  2075. ;  Returns:
  2076. ;        0 : OK
  2077. ;    non-0 : ERROR
  2078. ;
  2079. _rq_sense:
  2080.     moveq    #3,d2            ; do it 4 times
  2081.     move.w    #0,-(sp)        ; request 4 bytes of sense data
  2082.     bra.s    rq0
  2083. _rq_xsense:
  2084.     moveq    #0,d2            ; do it one time
  2085.     move.w    #16,-(sp)        ; request 16 bytes of sense data
  2086. rq0:    bsr    _delay            ; kludge delay
  2087.     movea.l    #wdc,a0
  2088.     st    flock            ; lock FIFO
  2089.     move.l    8(sp),-(sp)        ; -> sense data buffer address
  2090.     bsr    _setdma            ; set DMA there
  2091.     addq.l    #4,sp
  2092.  
  2093.      move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2094.     move.w    #$90,xwdl(a0)    ;wdl
  2095.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2096.  
  2097.     moveq    #0,d0
  2098. rq1:    move.w    #$88,xwdl(a0)    ;wdl
  2099.     move.w    6(sp),d0        ; d0 = (dev << 5) << 16
  2100.     lsl.b    #5,d0
  2101.     swap    d0            ; in upper word
  2102.     or.l    #$0003008a,d0        ; write dev#+Request Sense+FIFO bits
  2103.     move.l    d0,(a0)        ;wdcwdl    ; rqsense+dev wdc 8a wdl (byte 0)
  2104.     bsr    _qdone
  2105.     bmi.s    wdq1
  2106.  
  2107.     move.l    #$8a,d1        ; byte to be sent
  2108.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2109.     bsr    _qdone
  2110.     bmi.s    wdq1
  2111.  
  2112.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2113.     bsr    _qdone
  2114.     bmi.s    wdq1
  2115.  
  2116.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2117.     bsr    _qdone
  2118.     bmi.s    wdq1
  2119.  
  2120.     move.w    (sp),d0            ; # bytes of sense data requested
  2121.     swap    d0
  2122.     or.l    d1,d0
  2123.     move.l    d0,(a0)        ;wdcwdl    ; byte 4
  2124.     bsr    _qdone
  2125.     bmi.s    wdq1
  2126.  
  2127.     move.w    #$8a,xwdl(a0)    ;wdl
  2128.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2129.     move.w    #$8a,d0            ; wdl value
  2130.     bsr    _endcmd            ; wait for command completion
  2131.     tst.w    d0
  2132.     bmi.s    wdq1
  2133.     dbra    d2,rq1            ; go back until done
  2134. wdq1:    addq.l    #2,sp            ; clean up stack
  2135.     bra    _hdone
  2136.  
  2137.  
  2138. ;
  2139. ;----------------
  2140. ;
  2141. ;  testunit - Test Unit Ready
  2142. ;
  2143. ;    Synopsis:    LONG testunit(dev)
  2144. ;        WORD dev;        4(sp).W
  2145. ;
  2146. ;    Uses:  d0, d1, and a0
  2147. ;-
  2148. tst:    dc.b    0    ; format command + devno (upper 3 bits)
  2149.     dc.b    0    ; (unused)
  2150.     dc.b    0    ; (unused)
  2151.     dc.b    0    ; (unused)
  2152.     dc.b    0    ; (unused)
  2153.     dc.b    0    ; (unused)
  2154. .even
  2155.  
  2156. testunit:
  2157.     bsr    _delay
  2158.     move.w    4(sp),d0        ; set dev#
  2159.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2160.     move.b    d0,tst            ; stuff into command frame
  2161.     lea    tst(pc),a0        ; pick up pointer to the command block
  2162.     clr.w    d0
  2163.     st    flock            ; lock FIFO
  2164.     move.w    #$88,wdl
  2165.     move.b    (a0)+,d0        ; get the command byte
  2166.     swap    d0
  2167.     move.w    #$8a,d0
  2168.     move.l    d0,wdc            ; byte wdc 8a wdl
  2169.  
  2170.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2171. tst1:    bsr    _qdone
  2172.     bmi    _hto
  2173.     move.b    (a0)+,d0        ; next byte of command
  2174.     swap    d0
  2175.     move.w    #$8a,d0
  2176.     move.l    d0,wdcwdl
  2177.     dbra    d1,tst1
  2178.     bsr    _endcmd            ; wait for command completion
  2179.     bra    _hdone            ; cleanup after IRQ
  2180.  
  2181.  
  2182. ;
  2183. ;---------------- Resident Installer -------------------
  2184.  
  2185. isasi5:    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  2186.  
  2187.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  2188.     bls.s    nboot0        ; if not, don't need to replace GEMDOS buffers
  2189.                 ; else check if there is enough memory for
  2190. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  2191.     tst.l    d0        ; enough?
  2192.     bpl.s    okbig        ; if so, build the list
  2193.     move.w    minbigsect,d0    ; d0 = minimum big sector
  2194.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  2195.     bcc.s    regsect        ; if so, give up
  2196.     move.w    d0,maxssz    ; else try minimum big sector
  2197.     bra.s    chkmem
  2198. regsect:
  2199.     move.w    #512,maxssz    ; else, cannot handle big sectors
  2200.     bra.s    nboot0
  2201.  
  2202. okbig:    move.l    d1,tokeep    ; update amout of memory to be kept
  2203.     lea    i_sasi1,a0    ; a0 = ptr to beginning of new buffer lists
  2204.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  2205.     bsr    list_init    ; initialize the buffer list
  2206.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  2207.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  2208.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  2209.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  2210.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  2211.  
  2212. nboot0:    bsr    pool_install    ; attempt to install more OS pool
  2213.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  2214.     bne.s    nboot1        ; (already there)
  2215.     move.l    d0,-(sp)    ; save size of installed pool
  2216.     move.l    savssp,-(sp)    ; become a mild mannered user process
  2217.     move.w    #$20,-(sp)    ; Super(savssp)
  2218.     trap    #1
  2219.     addq.l    #6,sp
  2220.     move.l    (sp)+,d0    ; restore size of installed pool
  2221.  
  2222. nboot1:    add.l    tokeep,d0    ; compute value for Ptermres() or Mshrink
  2223.     tst.w    bootloaded    ; exit to GEMDOS?
  2224.     beq    nboot2        ; (yes -- not boot loaded)
  2225.  
  2226. ;+
  2227. ;  Return to TOS ROMs
  2228. ;    - set default boot device to C:
  2229. ;    - Print silly message
  2230. ;    - Mshrink() memory that was alloc'd to us
  2231. ;    - set magic# in D7 for TOS ROMs
  2232. ;    - RTS back to ROMs
  2233. ;-
  2234.     add.l    #$1c,d0        ; for file header
  2235.     move.l    d0,-(sp)    ; save D0
  2236.     pea    msg_loaded(pc)    ; print announcement
  2237.     move.w    #9,-(sp)
  2238.     trap    #1
  2239.     addq.l    #6,sp
  2240.     move.l    (sp)+,d0
  2241.  
  2242.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  2243.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  2244.     lea    pun,a0        ; a0 = ptr to pun table
  2245.     move.w    #0,d2        ; d2 = boot dev
  2246. bd1:    cmp.b    (a0,d2.w),d1    ; d2 belongs to physical unit booted from?
  2247.     beq    bd2        ; if yes, set (d2) as boot device
  2248.     addq.w    #1,d2        ; else try next logical unit
  2249.     bra.s    bd1
  2250. bd2:    addq.w    #2,d2        ; offset for drive A and B
  2251.     move.w    d2,_bootdev    ; set default boot device to (d2)
  2252.  
  2253.     move.l    d0,-(sp)
  2254.     move.l    baseaddr,-(sp)
  2255.     clr.w    -(sp)
  2256.     move.w    #$4a,-(sp)    ; Mshrink(...)
  2257.     trap    #1
  2258.     adda    #12,sp        ; (cleanup stack)
  2259.  
  2260.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  2261.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  2262.     trap    #1
  2263.     addq.l    #4,sp        ; cleanup stack
  2264.  
  2265.     move.l    #rootpath,-(sp)    ; set root as current directory
  2266.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  2267.     trap    #1
  2268.     addq.l    #6,sp        ; cleanup stack
  2269.  
  2270.     movea.l    _sysbase,a0    ; get the system header address
  2271.     move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  2272.     cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  2273.     bcs.s    stopall        ; yup, if OS is built before 4/22/87
  2274.     move.b    puns+1,d7    ; else prevent processed units from booting
  2275.     subq.b    #1,d7        ; unit # = # of units - 1
  2276.     lsl.b    #5,d7
  2277.     rts            ; return to TOS ROMs
  2278.  
  2279. stopall:
  2280.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  2281.     rts            ; return to TOS ROMs
  2282.  
  2283. rootpath:
  2284.     dc.b    '\\',0
  2285. msg_loaded:
  2286.     dc.b    '----------------------',13,10
  2287.     dc.b    'Atari Hard Disk Driver',13,10
  2288.     dc.b    'AHDI v3.00 May-15-1989',13,10
  2289.     dc.b    '----------------------',13,10
  2290.     dc.b    0
  2291. .even
  2292.  
  2293. ;
  2294. ;  Terminate and stay resident;
  2295. ;  installed driver under GEMDOS.
  2296. ;
  2297. nboot2:    add.l    #$0100,d0    ; for basepage
  2298.     move.w    #0,-(sp)    ; exit code
  2299.     move.l    d0,-(sp)
  2300.     move.w    #$31,-(sp)    ; terminate and stay resident
  2301.     trap    #1        ; should never come back...
  2302.     illegal
  2303.  
  2304.  
  2305.  
  2306. ;+
  2307. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  2308. ;
  2309. ; Passed:
  2310. ;     a0.l = head of buffer list            (not changed)
  2311. ;    d0.l = size of each BCB (including data block)    (not changed)
  2312. ;    d1.w = count
  2313. ;         = number of buffers to be installed to the list - 1
  2314. ;
  2315. ; Uses:
  2316. ;    d1, a1
  2317. ;-
  2318. list_init:
  2319.     move.l    a0,-(sp)    ; save head of buffer list
  2320. lin0:    movea.l    a0,a1        ; a1 = ptr to next BCB
  2321.     adda.l    d0,a1        ;    = ptr to curr BCB + size of BCB
  2322.     move.l    a1,(a0)        ; b_link -> next BCB
  2323.     move.w    #-1,4(a0)    ; b_neg1 = -1
  2324.     adda.w    #BCBLEN,a0    ; a0 = ptr to BCB data block
  2325.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  2326.     movea.l    a1,a0
  2327.     dbra    d1,lin0
  2328.     suba.l    d0,a0        ; a0 = ptr to last BCB
  2329.     clr.l    (a0)        ; lastBCB.b_link = NULL
  2330.     move.l    (sp)+,a0    ; restore head of buffer list
  2331.     rts
  2332.  
  2333.  
  2334. ;+
  2335. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  2336. ;        buffer lists
  2337. ;
  2338. ; Returns:
  2339. ;    d0.l = size of each BCB (including data block)
  2340. ;         or -1 if not enough memory is allocated
  2341. ;
  2342. ; Uses:
  2343. ;    d0, d1
  2344. ;-
  2345. chklstmem:
  2346.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  2347.     add.w    maxssz,d0    ;      = BCB header len + data block size
  2348.     move.l    d0,d1        ; d1.l = d0.l * 4 
  2349.     lsl.l    #2,d1        ;      = total size of buffer lists
  2350.     add.l    tokeep,d1    ; d1.l = size needed
  2351.     cmp.l    memalloc,d1    ; enough memory allocated?
  2352.     bls.s    chk0        ; if so return
  2353.     moveq    #-1,d0        ; else return error
  2354. chk0:    rts
  2355.  
  2356.  
  2357. ;
  2358. ;+
  2359. ; pread(sectno, cnt, buf, physunit, flag)
  2360. ; LONG sectno;
  2361. ; BYTE *buf; (word aligned)
  2362. ; WORD cnt,physunit,flag;
  2363. ;
  2364. ; Passed:    flag.w            $10(sp)    
  2365. ;        dev.w        $a(a0)    $e(sp)
  2366. ;        &buf.l        $6(a0)    $a(sp)
  2367. ;        cnt.w        $4(a0)    $8(sp)
  2368. ;        sectno.l    $0(a0)    $4(sp)
  2369. ;
  2370. ; flag = 1 -- return media change if detected
  2371. ; flag = 0 -- ignore media change
  2372. ;
  2373. ; Returns:    -1 if we could not read it
  2374. ;            (may not exist)
  2375. ;-
  2376. _pread:
  2377. pread:    move    _retries,retrycnt
  2378. pread1:    lea    4(sp),a0        ; frame pointer
  2379.     move.w    $a(a0),-(sp)        ; push physical unit number
  2380.     move.l    $6(a0),-(sp)        ; buffer address
  2381.     move.w    $4(a0),-(sp)        ; number to read
  2382.     move.l    (a0),-(sp)        ; sector number
  2383.     bsr    _hread            ; hread()
  2384.     adda    #12,sp            ; clean up stack
  2385.     tst.w    d0            ; read successful
  2386.     beq    pread8            ; if so, return
  2387.     bmi.s    pread9            ; timeout, does not exist
  2388.                     ; else, it's check condition status
  2389.     move.w    $e(sp),cpun        ; cpun = current physical unit #
  2390.     bsr    errcode            ; find error code
  2391.  
  2392.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  2393.     beq.s    preadd            ; if so, return drive not ready
  2394.  
  2395.     tst.w    $10(sp)            ; ignore media change?
  2396.     beq.s    preadc            ; if so, next try
  2397.                     ; else see if it's media change error
  2398.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  2399.     beq.s    pread7            ; if so, return media change
  2400.  
  2401. preadc:    subq    #1,retrycnt        ; else try try again
  2402.     bpl    pread1
  2403.  
  2404. pread9:    moveq    #EREADF,d0        ; read error
  2405.     rts
  2406.  
  2407. pread7:    moveq    #E_CHNG,d0        ; return media change detected
  2408.     rts
  2409.  
  2410. preadd:    moveq    #EDRVNR,d0        ; drive not ready
  2411.     rts
  2412.  
  2413. pread8:    clr.l    d0            ; flag no errors
  2414.     rts
  2415.  
  2416.  
  2417. ;
  2418. ;+
  2419. ; critic - call up the critical error handler.
  2420. ;
  2421. ; Passed:
  2422. ;    d0.w = error code
  2423. ;    d1.w = drive # excluding A: and B:
  2424. ;
  2425. ; Uses:
  2426. ;    d0, d1, a0
  2427. ;
  2428. ; Returns:
  2429. ;    d0.l = whatever returned by the critical handler
  2430. ;        (magic RETRY code or something)
  2431. ;-
  2432. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2433.     move.w    d1,-(sp)        ; drive #
  2434.     move.w    d0,-(sp)        ; error code
  2435.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2436.     jsr    (a0)            ; critic_handler(error, drive)
  2437.     addq.l    #4,sp            ; clean up stack
  2438.     rts                ; return
  2439.  
  2440.  
  2441. ;+
  2442. ; errcode - find error code for previous Check Condition Status
  2443. ;
  2444. ; Assumed:
  2445. ;    cpun = current physical unit number
  2446. ;
  2447. ; Returns:
  2448. ;    d0.b = error code    (aka additional sense code)
  2449. ;-
  2450. errcode:
  2451.     move.w    cpun,d0            ; d0 = physical unit number
  2452.     move.l    #sendata,-(sp)        ; sense data buffer
  2453.     move.w    d0,-(sp)        ; physical unit number
  2454.     btst.b    d0,scsi            ; embedded SCSI unit?
  2455.     beq.s    err0            ; if not, request non-extended sense
  2456.     bsr    _rq_xsense        ; else request extended sense
  2457.     tst.w    d0            ; successful?
  2458.     bne.s    err1            ; if not, return
  2459.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2460.     move.b    12(a0),d0        ; else d0.b = error code
  2461.     bra.s    err2            ; and return
  2462. err0:    bsr    _rq_sense        ; find out error code
  2463.     tst.w    d0            ; successful?
  2464.     bne.s    err1            ; if not, return
  2465.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2466.     move.b    (a0),d0            ; else d0.b = error code
  2467.     andi.b    #$7f,d0            ; mask valid bit
  2468.     bra.s    err2            ; and return
  2469. err1:    moveq    #-1,d0            ; error occurred
  2470. err2:    addq.l    #6,sp            ; cleanup stack
  2471.     rts
  2472.  
  2473.  
  2474. ;
  2475. ;----------------- OS Pool Expansion ------------------
  2476.  
  2477. .if ospool
  2478. ;---------------
  2479. ;
  2480. ;  Wire more pool into various ROM releases.
  2481. ;
  2482. ;    Passed:    nothing
  2483. ;    Returns:    D0 = #bytes extra used
  2484. ;
  2485. ;-
  2486. pool_install:
  2487.     move.l    _sysbase,a3        ; a3 -> base of OS
  2488.  
  2489. ; make sure we're in ROM,
  2490. ; then get address of RAM location to patch:
  2491.  
  2492.     cmp.l    #$800000,a3        ; better be ROM
  2493.     blt    notrom
  2494.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2495. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2496.     beq    badrom            ; (forget it, end of list)
  2497.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2498.     cmp.l    $18(a3),d1        ; match dates?
  2499.     bne.s    pi_lp            ; (no -- try again)
  2500.  
  2501.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2502.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2503.     move.l    d0,d1            ; d1 = total memory needed
  2504.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2505.     cmp.l    memalloc,d1        ; enough is allocated?
  2506.     bgt.s    bdrom2            ; if not, don't add any
  2507.                     ; else install more OS pool
  2508.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2509.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2510.     move.l    a0,-(sp)        ; save base of first buffer
  2511.     move.w    numchunks,d1        ; d0 = count-1
  2512.     subq.w    #1,d1
  2513. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2514.     move.l    a1,(a0)            ; buffer -> next one
  2515.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2516.     move.l    a1,a0            ; a0 -> next buffer
  2517.     dbra    d1,pin_1        ; (do some more)
  2518.  
  2519.     sub.w    #chunksiz,a0        ; a0 -> last block
  2520.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2521.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2522.     rts                ; return OK
  2523.  
  2524. ;+
  2525. ;  Print warning messages
  2526. ;  about bogus versions of the
  2527. ;  operating system.  Assume that
  2528. ;  every OS past 1-May-1986 has the
  2529. ;  pool fix installed.
  2530. ;
  2531. ;-
  2532. ok_date    =    %0000110010100001    ; 1-May-1986
  2533. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2534.     bra.s    bdrom1
  2535. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2536. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2537.     bcc    bdrom2            ; then don't print anything
  2538.  
  2539.     move.l    a0,-(sp)        ; print nasty message
  2540.     move.w    #9,-(sp)
  2541.     trap    #1
  2542.     addq.l    #6,sp
  2543.  
  2544. ; print msg and wait for RETURN
  2545.     pea    keymsg(pc)
  2546.     move.w    #9,-(sp)
  2547.     trap    #1
  2548.     addq.l    #6,sp
  2549.  
  2550. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2551.     move.w    #2,-(sp)
  2552.     trap    #13
  2553.     addq.l    #4,sp
  2554.     cmp.w    #13,d0
  2555.     bne    bdrom3
  2556.  
  2557. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2558.     rts
  2559.  
  2560. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2561.     dc.b    'key to continue:',13,10
  2562.     dc.b    0
  2563.  
  2564. m_notrom:
  2565.     dc.b    '*** WARNING ***',13,10,7
  2566.     dc.b    'This hard disk driver may not work with',13,10,7
  2567.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2568.     dc.b    'your hard disk may be damaged.',13,10,7
  2569.     dc.b    13,10,7
  2570.     dc.b    0
  2571.  
  2572. m_badrom:
  2573.     dc.b    '*** WARNING ***',13,10,7
  2574.     dc.b    'You are using an unofficial ROM release',13,10,7
  2575.     dc.b    'of the operating system.  This driver',13,10,7
  2576.     dc.b    'may not work correctly with it.  Files',13,10,7
  2577.     dc.b    'on your hard disk may be damaged.',13,10,7
  2578.     dc.b    13,10,7
  2579.     dc.b    0
  2580.     even
  2581.  
  2582.  
  2583. ;+
  2584. ;  Table of ROM release dates / _root addresses
  2585. ;  update these for new ROM releases that need the patch.
  2586. ;
  2587. ;-
  2588. pool_tab:
  2589.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2590.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2591.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2592.     dc.l    0            ; end of list
  2593.  
  2594. .endif
  2595.  
  2596.  
  2597. ;
  2598. ;------------------ Driver Installation -----------------
  2599.  
  2600. ;----------------
  2601. ;
  2602. ;  Driver Installation
  2603. ;
  2604. i_sasi1:
  2605.     move.l    d0,memalloc        ; record amount of memory available
  2606.     tst.w    bootloaded        ; if boot-loaded, don't Super()
  2607.     bne    nboot3
  2608.     clr.l    -(sp)            ; it's a bird...
  2609.     move.w    #$20,-(sp)        ;    ... it's a plane ...
  2610.     trap    #1            ;      ... no, its:
  2611.     addq.l    #6,sp            ; SOOUPERUSER!
  2612.     move.l    d0,savssp        ; "Faster than a prefetched opcode..."
  2613.  
  2614. nboot3:    move    #MAXUNITS-1,d1
  2615.     moveq    #-1,d0            ; a bad pun
  2616.     lea    pun,a0
  2617. i_sasi2:
  2618.     move.b    d0,(a0)+        ; initialize all puns to be bad
  2619.     dbra    d1,i_sasi2
  2620.  
  2621.     move    #0,clun            ; cur log unit# excluding drive A & B
  2622.     move.l    #4,cdbit        ; current drive bit
  2623.     move    #0,cpun            ; current physical unit number
  2624.     move    #0,puns            ; no physical units found
  2625.     move    minbigsect,maxssz    ; initialize maximum sector size
  2626.  
  2627.     move.l    _dskbufp,pbuf        ; pbuf = buffer address of
  2628.     add.l    #512,pbuf        ;     root sector image
  2629. i_sasi3:
  2630.     clr.w    -(sp)            ; ignore media change
  2631.     move.w    cpun,-(sp)        ; physical unit number
  2632.     move.l    pbuf,-(sp)        ; buffer
  2633.     move.w    #1,-(sp)        ; 1 sector
  2634.     move.l    #0,-(sp)        ; sectno = 0; root sector
  2635.     bsr    pread            ; pread()
  2636.     adda    #14,sp
  2637.     move.w    d0,preadret        ; save pread return code
  2638.  
  2639.     movea.l    #sendata,a0        ; a0 = address of sense data buffer
  2640.     clr.l    (a0)            ; fill buffer with 0's
  2641.     clr.l    4(a0)
  2642.     clr.l    8(a0)
  2643.     clr.l    $c(a0)
  2644.     move.l    a0,-(sp)        ; buffer for data inquired
  2645.     move.w    cpun,-(sp)        ; current physical unit
  2646.     bsr    _inquiry        ; inquiry(physunit, buf)
  2647.     addq.l    #6,sp            ; clean up stack
  2648.     tst.w    d0            ; Inquiry successful?
  2649.     bne.s    chkret            ; if not, unit isn't a SCSI device
  2650.                     ; else unit is a SCSI device
  2651.     movea.l    #sendata,a0        ; a0 = address of sense data
  2652.     tst.b    (a0)            ; is unit a hard drive?
  2653.     bne.s    i_sasi4            ; if not, end of chain
  2654.     move.w    cpun,d1            ; else d1 = physical unit #
  2655.     bset.b    d1,scsi            ; mark unit as embedded scsi
  2656.     btst.b    #7,1(a0)        ; removable drive?
  2657.     beq.s    chkret            ; if not removable, was read ok?
  2658.     bset.b    d1,rmbits        ; else mark unit as removable
  2659.     bra.s    found1
  2660. chkret:    tst.w    preadret        ; was pread successful?
  2661.     bne.s    i_sasi4            ; if not, not an ACSI unit, return
  2662. found1:    addq    #1,puns            ; else found a physical unit
  2663.     bsr    ppu            ; find out how it is partitioned
  2664.     tst.w    d0            ; ppu successful?
  2665.     beq.s    nxtpun            ; go on normally
  2666.                     ; else find out what's wrong
  2667.     cmpi.w    #E_CHNG,d0        ; media changed?
  2668.     beq    i_sasi3            ; if so, retry this unit
  2669.                     ; else try next physical unit
  2670. nxtpun:    addq.w    #1,cpun            ; next physical unit
  2671.     cmpi.w    #MAXACSI,cpun        ; last one yet?
  2672.     bne    i_sasi3            ; if not, continue
  2673.  
  2674. i_sasi4:
  2675.     clr.l    a5            ; zeropage ptr
  2676.     move.l    hdv_bpb(a5),o_bpb
  2677.     move.l    hdv_rw(a5),o_rw
  2678.     move.l    hdv_mediach(a5),o_mediach
  2679.  
  2680.     move.l    #hbpb,hdv_bpb(a5)    ; install our new ones
  2681.     move.l    #hrw,hdv_rw(a5)
  2682.     move.l    #hmediach,hdv_mediach(a5)
  2683.     move.l    #_puns,pun_ptr(a5)
  2684.  
  2685.     move.l    #_cookie,cookptr    ; initialize cookie pointer
  2686.     bra    isasi5            ; must get back into resident part
  2687.  
  2688.  
  2689. ;
  2690. ;-----------------
  2691. ;
  2692. ; Partition physical unit
  2693. ;
  2694. ;
  2695. ppu:    move.w    #0,npart        ; no partition found for cpun yet
  2696.     move.w    cpun,d1            ; is cpun removable?
  2697.     btst.b  d1,rmbits        ;
  2698.     beq.s    ppu0            ; if not, go on normally
  2699.                     ; else, it's a syquest unit
  2700.     tst.w    preadret        ; is there a cartridge in there?
  2701.     bne.s    squnit            ; if not, go reserve #drv letters
  2702.                     ; else find the partitions
  2703. ppu0:    moveq    #MAXNPART,d1        ; d1 = # partition entries to check
  2704.     movea.l    pbuf,a0            ; a0 = ptr to root sector image
  2705.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  2706.     bne.s    ppu1            ; if not, assume it's in ST format
  2707.     bsr    dosppu            ; else, handle it the DOS way
  2708.     bra.s    ppu2
  2709. ppu1:    bsr    gemppu
  2710. ppu2:    tst.w    d0            ; successful?
  2711.     bne.s    ppud            ; if not, return
  2712.  
  2713.     lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2714.     move.w    cpun,d1            ; d1 = unit #
  2715.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2716.     sub.w    npart,d1        ; enough drives being set up?
  2717.     bls.s    ppud            ; if so, done
  2718.                     ; else see if it's removable
  2719.     move.w    cpun,d0            ; d0 = unit #
  2720.     btst.b    d0,rmbits        ; is cpun removable?
  2721.     beq.s    ppud            ; if not, done
  2722.     bra.s    sq0            ; else, set up the rest
  2723.  
  2724. squnit:    lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2725.     move.w    cpun,d1            ; d1 = unit #
  2726.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2727. sq0:    subq.w    #1,d1
  2728. ppu3:    move.w    d1,-(sp)        ; save count
  2729.     bsr    nxtd0
  2730.     move.w    (sp)+,d1        ; restore count
  2731.     tst.w    d0            ; a valid unit?
  2732.     bmi.s    ppud            ; if not, return
  2733.     dbra    d1,ppu3
  2734. ppud:    rts
  2735.  
  2736.  
  2737. ;
  2738. ;+
  2739. ; dosppu - find the DOS partitions of the drive and set up
  2740. ;       appropiate data structures.
  2741. ; Passed:
  2742. ;    a0 = buffer address for root sector
  2743. ;    d1 = number of entries in partition map
  2744. ;
  2745. ; Returns:
  2746. ;    d0 = 0            if no error
  2747. ;       = negative #        if error found
  2748. ;-
  2749. dosppu:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  2750. dppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2751.     sf    ext            ; not dealing with ext partition
  2752.     bsr    fdpart            ; find partitions
  2753.     tst.b    d0            ; found any?
  2754.     beq.s    dppua            ; not a valid partition
  2755.     cmpi.b    #5,d0            ; extended partition?
  2756.     bne.s    dppu1            ; if not, it's a regular partition
  2757.     st    ext            ; else, it's an extended partition
  2758.     move.l    #0,extvol        ; offset from start of partition = 0
  2759.     move.l    d1,extrt        ; starting sector # of ext partition
  2760. dppux:    bsr    fdnxt            ; find next logical drive
  2761.     tst.b    d0            ; found any?
  2762.     beq.s    dppua            ; no logical drive found
  2763.     bmi.s    dppu2            ; error returned
  2764.     cmpi.b    #5,d0            ; extended volume?
  2765.     beq.s    dppux            ; if so, go find next logical drive
  2766. dppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2767.     bsr    nxtdrv            ; general set up for clun
  2768.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2769.     tst.w    d0            ; set up successful?
  2770.     beq.s    dppu3            ; if successful, continue
  2771. dppu2:    addq.l    #8,sp            ; else clean up stack
  2772.     bra.s    dppur            ; and return
  2773. dppu3:    tst.b    ext            ; clun is in ext partition?
  2774.     bne.s    dppux            ; if so, go find next ext vol
  2775. dppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2776.     adda    #16,a0            ; index to next entry in pmap
  2777.     dbra    d1,dppu0
  2778.     moveq    #0,d0            ; get here with no error!
  2779. dppur:    rts
  2780.  
  2781.  
  2782. ;
  2783. ;+
  2784. ; gemppu - find the GEMDOS partitions of the drive and set up
  2785. ;       appropiate data structures.
  2786. ; Passed:
  2787. ;    a0 = buffer address for root sector
  2788. ;    d1 = number of entries in partition map
  2789. ;
  2790. ; Returns:
  2791. ;    d0 = 0            if no error
  2792. ;       = negative #        if error found
  2793. ;-
  2794. gemppu:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  2795.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  2796.     beq.s    gppu4            ; if =0, no drive will exist
  2797. gppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2798.     sf    ext            ; not dealing with ext partition
  2799.     bsr    fgpart            ; find partitions
  2800.     tst.b    d0            ; found any?
  2801.     beq.s    gppua            ; not a valid partition
  2802.     cmpi.b    #'X',d0            ; extended partition?
  2803.     bne.s    gppu1            ; if not, it's a regular partition
  2804.     st    ext            ; else, it's an extended partition
  2805.     move.l    #0,extvol        ; offset from start of partition = 0
  2806.     move.l    d1,extrt        ; starting sector # of ext partition
  2807. gppux:    bsr    fgnxt            ; find next logical drive
  2808.     tst.b    d0            ; found any?
  2809.     beq.s    gppua            ; no logical drive found
  2810.     bmi.s    gppu2            ; error returned
  2811.     cmpi.b    #'X',d0            ; extended volume?
  2812.     beq.s    gppux            ; if so, go find next logical drive
  2813. gppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2814.     bsr    nxtdrv            ; general set up for clun
  2815.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2816.     tst.w    d0            ; set up successful?
  2817.     beq.s    gppu3            ; if so, continue
  2818. gppu2:    addq.l    #8,sp            ; else clean up stack
  2819.     bra.s    gppur            ; and return
  2820. gppu3:    tst.b    ext            ; clun is in ext partition?
  2821.     bne.s    gppux            ; if so, go find next ext vol
  2822. gppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2823.     adda    #12,a0            ; index to next entry in pmap
  2824.     dbra    d1,gppu0
  2825. gppu4:    moveq    #0,d0            ; get here with no error!
  2826. gppur:    rts
  2827.  
  2828.  
  2829. ;
  2830. ;+
  2831. ; nxtdrv    (of clun, cdbit)
  2832. ;
  2833. ; Passed:
  2834. ;    d1.l = starting sector # of clun
  2835. ; Returns:
  2836. ;    d0 = 0            if successful
  2837. ;       = negative #        if error occurred
  2838. ;-
  2839. nxtdrv:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  2840.     bge    nxtd9            ; yes, so signal error
  2841.  
  2842.     move.w    #1,-(sp)        ; return media change if detected
  2843.     move.w    cpun,-(sp)        ; physical unit number
  2844.     move.l    #sbuf,-(sp)        ; buffer address
  2845.     move.w    #1,-(sp)        ; 1 sector
  2846.     move.l    d1,-(sp)        ; logical sector 0 of clun
  2847.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  2848.     adda    #14,sp            ; clean up stack
  2849.     tst.w    d0            ; pread successful?
  2850.     bne    nxtr            ; if not, return with error code
  2851.  
  2852.     move.l    #sbuf,a0        ; a0 = addr of boot sector image
  2853.     moveq    #$b,d0            ; d0 = offset for bytes per sector
  2854.     bsr    getlhw
  2855.     tst.w    d0            ; bytes per sector = 0?
  2856.     beq.s    nxtd1            ; if so, assume ratio to be 1
  2857.  
  2858.     cmp.w    maxssz,d0        ; max sect size >= curr sect size?
  2859.     bls.s    nxtd00            ; if so, continue
  2860.     move.w    d0,maxssz        ; else max sect size = curr sect size
  2861. nxtd00:    divu    #512,d0            ; d0 = sector size ratio
  2862.     move.w    d0,sizr            ; sizr = sector size ratio
  2863.     bra.s    nxtd2            ; go on
  2864.  
  2865. nxtd0:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  2866.     bge    nxtd9            ; yes, so signal error
  2867.  
  2868. nxtd1:    move.w    #1,sizr            ; sector size ratio assumes to be 1
  2869.  
  2870. nxtd2:    move.l    cdbit,d1        ; get the bit to turn on
  2871.     move.l    _drvbits,d0        ; tell TOS we have the drive
  2872.     or.l    d1,d0
  2873.     move.l    d0,_drvbits
  2874.  
  2875.     asl.l    #1,d1            ; put in the next bit to turn on
  2876.     move.l    d1,cdbit
  2877.  
  2878.     move    clun,d0            ; d0 = dev number
  2879.     lea    pun,a0            ; a0 = ptr to pun table
  2880.     move.b    cpun+1,(a0,d0.w)    ; clun belongs to cpun
  2881.  
  2882.     lea    sratio,a0        ; a0 = ptr to sector size ratio table
  2883.     move.b    sizr+1,(a0,d0.w)    ; save sector ratio of clun
  2884.  
  2885.     lea    xst,a0            ; a0 = ptr to drive existence table
  2886.     move.b    #1,(a0,d0.w)        ; clun may exist
  2887.  
  2888.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  2889.     move.b    #2,(a0,d0.w)        ; clun is definitely changed
  2890.  
  2891.     addq    #1,clun            ; clun = next possible lun
  2892.     addq    #1,npart        ; one more partition found
  2893.     moveq    #0,d0            ; gets here with no error
  2894.     bra.s    nxtr
  2895.  
  2896. nxtd9:    moveq    #-1,d0            ; error!
  2897. nxtr:    rts
  2898.  
  2899.  
  2900. ;
  2901. .if    format
  2902. ;----------------
  2903. ;
  2904. ;  Parameter Block
  2905. ;
  2906. acfmt:    dc.b    4    ; format command + devno (upper 3 bits)
  2907.     dc.b    0    ; (unused)
  2908.     dc.b    0    ; (unused) data pattern
  2909. ac_in:    dc.b    0,0    ; interleave factor MSB, LSB
  2910.     dc.b    0    ; reserved
  2911. .even
  2912.  
  2913. ;---------------
  2914. ;
  2915. ;  _doformat - format hard disk
  2916. ;
  2917. ;    Synopsis:    LONG _doformat(dev, interlv)
  2918. ;        WORD dev;            4(sp).W
  2919. ;        WORD interlv;            6(sp).W
  2920. ;
  2921. _doformat:
  2922.     move.w    4(sp),d0        ; set dev#
  2923.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2924.     or.b    #4,d0            ; OR-in with FORMAT command
  2925.     move.b    d0,acfmt        ; stuff into command frame
  2926.     move.b    6(sp),ac_in        ; set interleave
  2927.     move.b    7(sp),ac_in+1
  2928.  
  2929.     lea    acfmt(pc),a0        ; pick up pointer to the command block
  2930.     clr.w    d0
  2931.     st    flock            ; lock FIFO
  2932.     move.w    #$88,wdl
  2933.     move.b    (a0)+,d0        ; get the command byte
  2934.     swap    d0
  2935.     move.w    #$8a,d0
  2936.     move.l    d0,wdc            ; byte wdc 8a wdl
  2937.  
  2938.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2939. fmt1:    bsr    _qdone
  2940.     bmi    _hto
  2941.     move.b    (a0)+,d0        ; next byte of command
  2942.     swap    d0
  2943.     move.w    #$8a,d0
  2944.     move.l    d0,wdcwdl
  2945.     dbra    d1,fmt1
  2946.     bsr    _endcmd            ; wait for command completion
  2947.     bra    _hdone            ; cleanup after IRQ
  2948.  
  2949.  
  2950. ;
  2951. ;----------------
  2952. ;
  2953. ;  _mode_set - set hard disk format parameters
  2954. ;
  2955. ;    Synopsis:    LONG _mode_set(dev, len, parms)
  2956. ;        WORD dev;            4(sp).W
  2957. ;        WORD len;            6(sp).W
  2958. ;        char *parms;            8(sp).L
  2959. ;
  2960. _mode_set:
  2961.     st    flock            ; lock FIFO
  2962.     move.l    8(sp),-(sp)        ; -> parameter block address
  2963.     bsr    _setdma            ; set DMA there
  2964.     addq.l    #4,sp
  2965.  
  2966. ; write command and dev#
  2967.     move.w    #$88,wdl
  2968.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  2969.     lsl.b    #5,d0
  2970.     swap    d0            ; in upper word
  2971.     or.l    #$0015008a,d0        ; write dev# + ModeSelect + FIFO bits
  2972.     move.l    d0,wdcwdl        ; mdsel+dev wdc 8a wdl (byte 0)
  2973.     bsr    _qdone
  2974.     bmi    wdx
  2975.  
  2976.     move.l    #$0000008a,wdcwdl    ; byte 1
  2977.     bsr    _qdone
  2978.     bmi    wdx
  2979.  
  2980.     move.l    #$0000008a,wdcwdl    ; byte 2
  2981.     bsr    _qdone
  2982.     bmi    wdx
  2983.  
  2984.     move.l    #$0000008a,wdcwdl    ; byte 3
  2985.     bsr    _qdone
  2986.     bmi    wdx
  2987.  
  2988.     move.w    6(sp),d0        ; # bytes of parameter
  2989.     swap    d0            ; in upper word
  2990.     or.l    #$0000008a,d0
  2991.     move.l    d0,wdcwdl        ; byte 4
  2992.     bsr    _qdone
  2993.     bmi    wdx
  2994.  
  2995.     move.w    #$90,wdl        ; reset the DMA chip
  2996.     move.w    #$190,wdl
  2997.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  2998.     move.w    #$18a,wdl
  2999.     move.l    #$00000100,wdcwdl    ; byte 5 (control byte)
  3000.     move.w    #$18a,d0        ; wdl value
  3001.     bsr    _endcmd            ; wait for command completion
  3002. wdx:    bra    _hdone
  3003.  
  3004. .endif  ; format
  3005.  
  3006.   
  3007. .if    mdsense
  3008. ;----------------
  3009. ;
  3010. ;  _md_sense - get hard disk format parameters
  3011. ;
  3012. ;    Synopsis:    LONG _md_sense(dev, parms)
  3013. ;        WORD dev;            4(sp).W
  3014. ;        char *parms;            6(sp).L
  3015. ;
  3016. _md_sense:
  3017.     st    flock            ; lock FIFO
  3018.     move.l    6(sp),-(sp)        ; -> parameter block address
  3019.     bsr    _setdma            ; set DMA there
  3020.     addq.l    #4,sp
  3021.  
  3022. ; write command and dev#
  3023.     move.w    #$88,wdl
  3024.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  3025.     lsl.b    #5,d0
  3026.     swap    d0            ; in upper word
  3027.     or.l    #$001a008a,d0        ; write dev# + ModeSense + FIFO bits
  3028.     move.l    d0,wdcwdl        ; mdsense+dev wdc 8a wdl (byte 0)
  3029.     bsr    _qdone
  3030.     bmi    wdx1
  3031.  
  3032.     move.l    #$0000008a,wdcwdl    ; byte 1
  3033.     bsr    _qdone
  3034.     bmi    wdx1
  3035.  
  3036.     move.l    #$0000008a,wdcwdl    ; byte 2
  3037.     bsr    _qdone
  3038.     bmi    wdx1
  3039.  
  3040.     move.l    #$0000008a,wdcwdl    ; byte 3
  3041.     bsr    _qdone
  3042.     bmi    wdx1
  3043.  
  3044.     move.l    #$0016008a,wdcwdl    ; 22 bytes of parameters (byte 4)
  3045.     bsr    _qdone
  3046.     bmi    wdx1
  3047.  
  3048.     move.w    #$190,wdl        ; reset the DMA chip
  3049.     move.w    #$90,wdl
  3050.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  3051.     move.w    #$8a,wdl
  3052.     move.l    #0,wdcwdl        ; byte 5 (control byte)
  3053.     move.w    #$8a,d0            ; wdl value
  3054.     bsr    _endcmd            ; wait for command completion
  3055. wdx1:    bra    _hdone
  3056.  
  3057. .endif  ; mdsense
  3058.  
  3059.     bss
  3060. clun:    ds.w    1            ; current logical unit
  3061. cdbit:    ds.l    1            ; current drive bit
  3062. sbuf:    ds.b    512            ; temporary buffer for i/o
  3063.     end
  3064.